生成序列

【题目描述】

给定一个不小于 2 的整数 k,按照如下方式生成一个无限长的序列 S (下标从 0
开始)。

  1. 初始时序列只有一个元素 S 0 = 0。
  2. 对于 j = 1; 2; · · · ; k − 1 分别把当前序列的每个元素都加上 j,得到新的 k − 1 个
    序列。
  3. 把新的 k − 1 个序列依次接在当前序列后面,得到一个长度为当前序列长度 k 倍
    的序列。
  4. 把这个序列每一项都变成其除以 k 之后的余数,并把这个序列作为新的当前序
    列。
  5. 执行无穷次操作 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;
}
posted @ 2020-10-05 21:00  wuwendongxi  阅读(216)  评论(0编辑  收藏  举报