【题目描述】
给定一个不小于 2 的整数 k,按照如下方式生成一个无限长的序列 S (下标从 0
开始)。
- 初始时序列只有一个元素 S 0 = 0。
- 对于 j = 1; 2; · · · ; k − 1 分别把当前序列的每个元素都加上 j,得到新的 k − 1 个
序列。 - 把新的 k − 1 个序列依次接在当前序列后面,得到一个长度为当前序列长度 k 倍
的序列。 - 把这个序列每一项都变成其除以 k 之后的余数,并把这个序列作为新的当前序
列。 - 执行无穷次操作 2 − 4。
例如 k = 3,每一轮执行之后的序列分别是:
012
012 120 201
012120201 120201012 201012120
· · · · · ·
例如 k = 2,则序列是 01101001100101101001011001101001 · · ·
现在给定正整数 L; R,你需要求 ∑R i=L h(i) × S i 的值,并输出答案对 232 取模的结
果,其中 h(i) = ⌊ [i mod 20000116] 233 2+i+804⌋。
【输入格式】
从文件 b.in 中读入数据。
第一行一个正整数 T,表示数据组数。
接下来 T 行每行三个正整数 k; L; R 表示一组数据,其中 k 用于生成序列 S, L; R
意义见所求和式。
【输出格式】
输出到文件 b.out 中。
对于每组数据,输出一行一个整数表示 ∑R i=L h(i) × S i 的值对 232 取模的结果。
【样例 1 输入】
10
2 1 10
3 1 10
4 1 10
5 1 10
2 1001 5005
10 123 456
233 1024 6174
16 10000 20000
20 12345678 23456789
987 2333123456789 2333198765432
【样例 1 输出】
15
36
51
66
89026303
599966
84450304
2099970147
3683804069
1796954653
思路
-
实现:暴力求出l的数位和,然后模拟进位
-
注意到没有mod 2^32,因为unsigned int最大值为(1<<32)
-
多次使用mod会导致超时,故用
temp=(l-1)%mod;
,if(++temp==mod) temp=0;
代替
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int mod=20000116;
long long l,r,temp;
int d[70],k,cnt,v,sum;
unsigned int ans;
inline void init(long long x)
{
ans=0;sum=0;cnt=0;
for(int i=0;i<=64;++i) d[i]=0;
while(x) sum+=(d[++cnt]=x%k),x/=k;
}
int main()
{
int T; scanf("%d",&T);
while(T--)
{
scanf("%d%lld%lld",&k,&l,&r);
init(l);
temp=(l-1)%mod;
for(long long i=l;i<=r;++i)
{
if(++temp==mod) temp=0;
v=(temp*temp+i+804)/233; ans+=(unsigned int)v*(sum%k);
++d[1]; ++sum;
for(int j=1;d[j]==k;++j) d[j]=0,++d[j+1],sum-=(k-1);
}
cout<<ans<<endl;
}
return 0;
}