luogu P5495 Dirichlet 前缀和
题面传送门
根据唯一分解定理,可以将每个数分解成\(\prod\limits_i{p_i^{a_i}}\),如果\(X|Y\),则充要于所有\(X_{a_i}\leq Y_{a_i}\)
则这个相当于对于每个质数次幂的高维前缀和。
考虑二维前缀和的除了容斥以外的一般写法,即先在第一维\(F_{i,j}=F_{i,j}+F_{i-1,j}\),再第二维\(F_{i,j}=F_{i,j-1}+F_{i,j}\)
所以可以扩展到高维前缀和,即对于每个质数向后拓展。根据埃氏筛的复杂度分析,是\(O(n\log\log n)\)的。
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 20000000
#define M N*N+5
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
using namespace std;
U seed;I U getnext(){seed^=seed<<13;seed^=seed>>17;seed^=seed<<5;return seed;}
int n,Fl[N+5],pr[N+5],ph;U A[N+5];
int main(){
freopen("1.in","r",stdin);
RI i,j;scanf("%d%u",&n,&seed);for(i=1;i<=n;i++) A[i]=getnext();
for(i=2;i<=n;i++){
if(!Fl[i]){pr[++ph]=i;for(j=1;j*i<=n;j++) A[j*i]+=A[j];}
for(j=1;j<=ph&&i*pr[j]<=n;j++){Fl[i*pr[j]]=1;if(i%pr[j]==0) break;}
}for(i=1;i<=n;i++) A[0]^=A[i];printf("%u\n",A[0]);
}