分析:
可以先暴力 枚举倍数:
点击查看代码
for(reg uint i=1;i<=n;i++)
for(reg uint k=1;k*i<=n;k++)
b[k*i]+=a[i];
for(uint i=1;i<=n;i++)
ans^=b[i];
但这样显然过不了 在枚举下标时会多次无意义枚举
关于唯一分解定理:
\(i\) 和 \(k\) 都可以分解为 \(\sum_{i=1}^np_i^{c_i}\) 和 \(\sum_{i=1}^mp_i^{c_i}\)
若 \(i\) 为 \(k\) 的因数 那么 \(i\) 分解出的每个 \(p_i\) 的指数 \(c_i\) 都会小于 \(k\) 分解出的 这时就会有贡献
所以枚举 \(i\) 就可以换成枚举 \(p_i\) 然后用类似前缀和的方式计算贡献
CODE:
点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define reg register
using namespace std;
typedef long long ll;
#define uint unsigned int
const int N=2e7+5;
uint seed;
inline uint getnext()
{
seed^=seed<<13;
seed^=seed>>17;
seed^=seed<<5;
return seed;
}
uint n,a[N],ans,tot,prime[N];
bool isprime[N];
void Prime()
{
isprime[1]=0;
for(int i=2;i<=N;i++)
{
if(isprime[i]) prime[++tot]=i;
for(int j=1;j<=tot&&i*prime[j]<=N;j++)
{
isprime[i*prime[j]]=0;
if(i%prime[j]==0) break;
}
}
}
int main(){
memset(isprime,1,sizeof isprime);
Prime();
scanf("%u%u",&n,&seed);
for(uint i=1;i<=n;i++)
a[i]=getnext();
for(reg uint i=1;i<=tot;i++)
for(reg uint k=1;k*prime[i]<=n;k++)
a[k*prime[i]]+=a[k];
for(uint i=1;i<=n;i++)
ans^=a[i];
printf("%u",ans);
return 0;
}