题意:
就是给你n,让你求出i从1到n,i的n次方的异或和。
思考:
如果直接对1到n每次求ksm,肯定会超时。其实这种题只要范围比较大,一般都是线性筛,要么是O(nlogn)这个数会出现多少次:many sum。要么就是O(n)的筛法:有毒的玻璃球。要么就是欧拉晒中间取维护一些东西。这题用到了一个性质就是任何一个数都可以表示为一个质数和另一个数的乘积,所以每次求ksm只会对质数求罢了,别的都是直接晒出来。
代码:
欧拉晒维护一些值:
int T,n,m,k;
ll res[N];
bool st[N];
int pri[N],cnt;
ll ksm(ll a,ll b)
{
ll sum = 1;
while(b)
{
if(b&1) sum = sum*a%mod;
b >>= 1;
a = a*a%mod;
}
return sum;
}
void init(int x)
{
res[1] = 1;
for(int i=2;i<=x;i++)
{
if(!st[i])
{
pri[++cnt] = i;
res[i] = ksm(i,n)%mod;
}
for(int j=1;pri[j]*i<=x;j++)
{
st[pri[j]*i] = 1;
res[pri[j]*i] = res[i]*res[pri[j]]%mod; //i*pri[j]可以直接被表示出来,这里res[i]和res[pri[j]]的值肯定已经晒出来过了
if(i%pri[j]==0) break;
}
}
}
signed main()
{
IOS;
cin>>n;
init(n);
ll anw = 0;
for(int i=1;i<=n;i++) anw ^= res[i];
cout<<anw;
return 0;
}
many sum代码:
int T,n,m,k;
int va[N];
int sum[N];
void init()
{
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j+=i)
sum[j] += va[i];
}
}
signed main()
{
IOS;
cin>>n>>va[1]>>m;
for(int i=2;i<=n;i++) va[i] = (va[i-1]+7*i)%m;
init();
int ans = 0;
for(int i=1;i<=n;i++) ans ^= sum[i];
cout<<ans;
return 0;
}
有毒的玻璃球代码:
int T,n,m,k;
int va[N];
int sum[N];
int ksm(int a,int b)
{
int sum = 1;
while(b)
{
if(b&1) sum = sum*a%mod;
a = a*a%mod;
b >>= 1;
}
return sum;
}
signed main()
{
IOS;
cin>>n>>m;
int ans = 0;
for(int i=1;i<=n;i++)
{
int sum = n/i;
ans = (ans+sum*ksm(i,m)%mod)%mod;
}
cout<<ans;
return 0;
}
总结:
多多积累经验呀,就和以前做过的题或者学过的算法联合起来。