新赛道-2024.8 CSP-J组月赛-T1总结
题面:
王老师 最近做了一道经典问题《翻纸牌》
现在 王老师 有 n 张牌,编号分别为 1,2,3…n,每张牌一开始都是背面朝上的
现在他要进行 n 轮操作,第 i 轮操作时候,他会将所有编号是 i 的倍数的牌正反翻面
现在 王老师 想知道,当他进行完 n 轮操作以后,所有正面朝上的牌的编号总和是多少
因为数字可能很大,所以请你将答案对 109+7 取模
对于 30% 的数据:1≤n≤106
对于 60% 的数据:1≤n≤1014
对于 100% 的数据:1≤n≤1018
从题中可知将n翻面的只有n的因子,而翻到正面的数字的因子个数一定是奇数,也就是完全平方数,再套入公式:n*(n+1)*(2*n+1)/6即可,但数据量为1e18,这么算会爆long long (我就是这么写挂的。。),所以需要用到特殊处理,首先,我们知道n*(n+1)%2==0,所以可以先算n*(n+1)/2,剩下的/3分两种情况讨论
设v=sqrt(n),x=v*(v+1)/2
1.若x%3==0,那么直接先将x/3%mod*(2*v+1)%mod;
2.否则把/3丢给(2*v+1):x%mod*((2*v+1)/3)%mod
代码:
#include <bits/stdc++.h>
using namespace std;
const unsigned long long mod=1e9+7;
unsigned long long n;
int main(){
//freopen("card.in","r",stdin);
//freopen("card.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
unsigned long long op=sqrt(n);
unsigned long long ans=op*(op+1)/2;
if(ans%3==0)cout<<ans/3%mod*(2*op+1)%mod;
else cout<<ans%mod*((2*op+1)/3)%mod;
return 0;
}
总结:在做题时需观看数据量判断其会不会爆,在进行处理,我在估数据量时还是比较弱,以后在打代码前应估计在中途会不会爆,再写代码。