原题解链接:https://ac.nowcoder.com/discuss/149990
令为中的出现次数。
首先对于每个 考虑 , 我们发现如果 ,那么,是一个区间。 所以我们可以首先枚举,再枚举的倍数,然后把统计进答案即可。
然后考虑。我们发现当从变为时,这个值多了。所以我们可以对于每个,枚举它的倍数,然后往这个倍数的位置打上的标记,最后前缀和即可求出每个位置的答案。
但是这样做的复杂度为(当都很小时)。
改进一下,如果有多个的值相同,那么这些打的标记都相同。所以我们可以改为枚举每个值,枚举的倍数,然后一次就打的标记。
复杂度为。
#include<bits/stdc++.h>
#define maxn 2000010
#define ll long long
using namespace std;
int a[maxn],b[maxn],n,m;
ll tag[maxn],ans=0;
inline void read(int &x){
char ch=x=0;
while(!isdigit(ch))
ch=getchar();
while(isdigit(ch))
x=x*10+ch-'0',ch=getchar();
}
int main(){
read(n),read(m);
for(int i=1;i<=n;i++)
read(a[i]),b[a[i]]++;
for(int i=1;i<=m;i++){
for(int j=i;j<=m;j+=i)
tag[j]+=b[i];
}
for(int i=1;i<=m;i++)
b[i]+=b[i-1],tag[i]+=tag[i-1];
for(int i=1;i<=m;i++){
for(int j=1;j*i<=m;j++){
int st=i*j,ed=min(m,i*(j+1)-1);
tag[i]+=1LL*(b[ed]-b[st-1])*j;
}
}
for(int i=1;i<=m;i++)
ans^=tag[i];
printf("%lld\n",ans);
return 0;
}