蓝桥杯 历届试题 数字游戏

题目链接:http://www.dotcpp.com/oj/problem1443.html(最近蓝桥一直举办校内赛可能服务器压力大卡的不行,而且这个网站没登陆也能查看题面比较方便一点)

蓝桥杯 历届试题 数字游戏_第1张图片

先看到数据规模,如果纯暴力的话10^6 * 10^6肯定是要超时的,所以我们要想办法优化,因为我们只关心栋栋报出的数字总和,我们又知道了其他人报的规律是前面一个人的+1 +2 +3 +4这样报的,那么换句话来说,我们只要知道每循环一组总共加了多少,把这些总和加起来加到栋栋上次报的数字上,就能知道栋栋这次报的数字就多少了,再换句话说就是只需要等差数列求和就得出来了。
.
不考虑k的情况,假设有3个人报数
.
假定要知道第二个报的情况,只需要把这一轮的等差数列求和加到上次报的数字上就好了

然后忘记了等差数列的求和公式是什么,就开始推,然后就想了一下比较经典的1+2+3+…+100那个,大概就推到首尾项相加乘个数除以二,得出 n ( a n + a 1 ) / 2 n(a_n+a_1)/2 n(an+a1)/2,最后考虑k的情况,因为每次要报到k的时候从0开始报,实质上就是对k取余,这也是写这篇博客的原因,因为大家都知道(a*b)%k=(a%k+b%k)%k,然后套上去的时候我一不小心对 a n 和 a 1 a_n和a_1 ana1也取余了,结果疯狂WA,而且还能过部分数据不是全WA,当时还以为是我的求和公式推错了,上网搜了一下发现也没用我这种式子的(再次吐槽一下,好多人真的是复制粘贴代码就发博客啊),那时候刚好在和一个朋友聊天,然后朋友也说这个式子是可行的
蓝桥杯 历届试题 数字游戏_第2张图片
最后就发现了是我手贱多打了两个取余,当然,至于 ( n ( a 1 % k + a n % k ) / 2 ) % k ! = S n % k (n(a_1\%k+a_n\%k)/2)\%k!=S_n\%k (n(a1%k+an%k)/2)%k!=Sn%k这里也是能通过数学证明的,这里就不详细展开了。
最后发一下AC代码,这里写的稍微“啰嗦了点”,本来很多能省略的,例如 a n a_n an是能通过 a 1 a_1 a1推出来的,不过我觉得这样写也增加了可读性,更符合数学公式

#include
using namespace std;
long long ans=1,next_num=1,total,an,a1;
int main()
{
	int n,k,t;
	cin>>n>>k>>t;
	ans=1;
	an=n;
	a1=1;
	for(int i=1;i<t;i++)
	{
		next_num=(next_num+(n*(an+a1)/2)%k)%k;
		ans+=next_num;
		a1=an+1;
		an=an+n;
	}
	cout<<ans;
	return 0;
}

你可能感兴趣的:(算法,C++,蓝桥杯)