问题描述: 给定人的个数n, 取的模值k, 栋栋要报的数字个数T, 求T个数字之和
问题分析: 本题最直接的做法是 模拟这个报数的过程,每两个人之间的差值 在逐渐增加,每次都加一。把每个人要报的数 放在一个sayDigit数组里,这个数组保留n个元素,分别是每轮每个人要报的数,当栋栋报完之后,立即累加到结果中。
代码展示:
#include <iostream>
using namespace std;
int main(){
int n,k,T;
cin>>n>>k>>T;
int sayDigital[n]; //表示n个人说出的数字序列
long long result = 0;
//等栋栋报完,立即将报的数累加
int i = 0;
int j = 0;
sayDigital[0] = 1;
result += sayDigital[0];
int step = 1;
do{
j = i;
i = (i+1)%n;
sayDigital[i] = (sayDigital[j] + step)%k;
step = (step+1)%k;
if(i==0){
result += sayDigital[i];
T--;
}
}while(T>1);
cout<<result<<endl;
return 0;
}
不幸的是,上述方法只能得到66分,做法没错,只是数据量过大,后两组数据超时了。
方法2:通过观察数据,我得到了下面的规律,假设用num[i]表示栋栋要报的第i个数,则num[1] = 1, 意思是栋栋报的第一个数是1.
当i > 1时,num[i] = (n*(n+1)/2 + n*n*(i-2) + num[i-1])%k 有了这个规律后,我们只要将num数组前T个元素累加即可。
规律解释:上式的推出是找规律得出的。
不管有几个人,他们要报的数是以下序列(先不考虑取模): 1,2,4,7,11,16,22,29,37,46,56,67,79……
那么当n=2时,栋栋要报的数是1,4,11,22,37…… 1和4之间差3,4和11之间差7,11和22之间差11. 由此发现差的值,3,7,11它们之间竟然总是4。 4=2*2=n*n, 而差值初值3不就是2*(2+1)/2=n*(n+1)/2嘛
当n=3,栋栋要报的数是1,7,22,46…… 1和7之间差6,7和22之间差15,22和46之间差24. 由此发现差的值,6,15,22它们之间竟然总是9。 9=3*3=n*n, 而差值初值6不就是3*(3+1)/2=n*(n+1)/2嘛
代码展示:
//AC代码
#include <iostream>
using namespace std;
int main(){
long long n,k,T;
cin>>n>>k>>T;
long long result = 0;
long long num[1000001];
num[1] = 1;
result += num[1];
for(int i=2;i<=T;i++){
num[i] = (n*(n+1)/2+n*n*(i-2)+num[i-1])%k;
result += num[i];
}
cout<<result<<endl;
return 0;
}
这里千万注意,n,k,T 要定义成long long型,以为for循环里面涉及到n*n的计算,在内存中是将n*n的值先赋值给n的,所以要把n的类型定成long long, 不然不能得100分呐,血的教训。