Atcoder Beginner Contest 212 G,H题解
作者:互联网
G
Description
∀ x ∈ [ 0 , P ) \forall x \in [0,P) ∀x∈[0,P),求满足 x n ≡ y ( m o d p ) x^n \equiv y \pmod p xn≡y(modp) 的自然数 ( x , y ) (x,y) (x,y) 对数。
Solution
为方便叙述,令 m = n − 1 m=n-1 m=n−1。
Lemma
答案为 ∑ i ∣ m i φ ( i ) + 1 \sum_{i|m} i\varphi(i)+1 i∣m∑iφ(i)+1
Prove
首先, x = 0 x=0 x=0 与 y = 0 y=0 y=0 对应,且 y = 0 y=0 y=0 仅与 x = 0 x=0 x=0 对应。下面,我们暂且先不管这一个配对。
首先,我们令 m m m 的原根为 r r r。根据原根的性质, r 1 , ⋯ , r p − 1 r^1,\cdots,r^{p-1} r1,⋯,rp−1 将 [ 1 , P ) [1,P) [1,P) 中的所有位置都覆盖了恰好一次。因此,当 x ≡ r a x \equiv r^a x≡ra 且 y ≡ r b y \equiv r^b y≡rb 时,有
r a n ≡ r b ( m o d P ) r^{an} \equiv r^b \pmod P ran≡rb(modP)
因此, a n ≡ b ( m o d m ) an \equiv b \pmod m an≡b(modm)。现在问题转化为,对于每个 a ∈ [ 0 , m ] a \in [0,m] a∈[0,m],求出 a , 2 a , 3 a , ⋯ a,2a,3a,\cdots a,2a,3a,⋯ 在模 m m m 意义下覆盖的位置数量。显然,这个数量是 m gcd ( m , a ) \frac {m} {\gcd(m,a)} gcd(m,a)m。
得到答案
∑ a = 1 m m gcd ( m , a ) \sum_{a=1}^m \frac {m} {\gcd(m,a)} a=1∑mgcd(m,a)m
令 d = gcd ( m , a ) d=\gcd(m,a) d=gcd(m,a),则式子可以被写作
∑ d ∣ m φ ( m d ) m d \sum_{d|m} \varphi(\frac m d)\frac m d d∣m∑φ(dm)dm
即
∑ d ∣ m d φ ( d ) \sum_{d|m} d \varphi (d) d∣m∑dφ(d)
引理证毕。
Algorithm
我们将 m m m 分解质因数,然后进行暴力搜索即可。同时维护两个量,表示当前搜索到的数的值,以及所有被选质因数的乘积和它们减 1 1 1 的乘积,可以非常方便地 O ( 1 ) O(1) O(1) 计算 φ \varphi φ。
时间复杂度 O ( f ( m ) ) O(f(m)) O(f(m)),其中 f ( m ) f(m) f(m) 表示 m m m 的约数个数。
Code
const int maxl=1005,mod=998244353;
int n,pos,ans;
int p[maxl],q[maxl];
void solve(int now,int val,int totp,int totp1){
if (now==pos+1){
int phi=(val/totp)*totp1;
ans=(ans+(((val)%mod*(phi%mod))%mod))%mod;
return;
}
int tmp=1;
for (int i=0;i<=q[now];i++){
solve(now+1,val*tmp,totp,totp1);
tmp*=p[now];
if (i==0) totp=totp*p[now],totp1=totp1*(p[now]-1);
}
}
signed main(){
cin>>n;n--;
for (int i=2;i*i<=n;i++){
if (n%i==0){
int cnt=0;
while (n%i==0) n/=i,cnt++;
p[++pos]=i,q[pos]=cnt;
}
}
if (n>1) p[++pos]=n,q[pos]=1;
solve(1,1,1,1);
cout<<(ans+1)%mod<<endl;
return 0;
}
H
Description
Solution
令 a i a_i ai 为 i i i 出现的次数, F ( x ) F(x) F(x) 为异或多项式且 f i = a i f_i=a_i fi=ai,则答案为 G ( x ) G(x) G(x) 的非 0 0 0 项系数之和。其中
G ( x ) = ∑ i = 1 m F ( x ) i G(x)=\sum_{i=1}^m F(x)^i G(x)=i=1∑mF(x)i
则
G ( x ) = F ( x ) m + 1 − F ( x ) F ( x ) − 1 G(x)=\frac {F(x)^{m+1}-F(x)} {F(x)-1} G(x)=F(x)−1F(x)m+1−F(x)
对 f f f 做 FWT 的异或变换,并对于每一位 x = f i x=f_i x=fi 将其变为 x m + 1 − x x − 1 \frac {x^{m+1}-x} {x-1} x−1xm+1−x,最后逆变换回去即可得到 G ( x ) G(x) G(x) 的每一项系数。注意特判 x = 1 x=1 x=1 的情况。
时间复杂度 O ( m log m ) O(m \log m) O(mlogm),其中 m = max { A i } m=\max \{A_i\} m=max{Ai}。
Code
const int maxl=200005,mod=998244353,inv2=499122177;
int n,k,maxv,p=1,ans;
int a[maxl];
int quick_power(int x,int y){
int res=1;
for (;y;y=y>>1,x=(x*x)%mod){
if (y&1) res=(res*x)%mod;
}
return res;
}
int ny(int tmpx){return quick_power(tmpx,mod-2);}
void FWT_xor_1(int l,int r){
if (l==r) return;
int mid=(l+r)>>1;
for (int i=0;i<r-mid;i++){
int u=a[l+i],v=a[mid+1+i];
a[l+i]=(u+v)%mod;
a[mid+1+i]=(u+mod-v)%mod;
}
FWT_xor_1(l,mid),FWT_xor_1(mid+1,r);
}
void FWT_xor_2(int l,int r){
if (l==r) return;
int mid=(l+r)>>1;
for (int i=0;i<r-mid;i++){
int u=a[l+i],v=a[mid+1+i];
a[l+i]=((u+v)*inv2)%mod;
a[mid+1+i]=((u+mod-v)*inv2)%mod;
}
FWT_xor_2(l,mid),FWT_xor_2(mid+1,r);
}
signed main(){
k=read(),n=read();
for (int i=1;i<=n;i++){
int x=read();
a[x]++;
maxv=max(maxv,x);
}
while (p<=maxv) p*=2;
p--;
FWT_xor_1(0,p);
for (int i=0;i<=p;i++){
if (a[i]==1){
a[i]=k;
continue;
}
int x=quick_power(a[i],k+1)-a[i];
x=(x%mod+mod)%mod;
int y=(a[i]+mod-1)%mod;
a[i]=(x*ny(y))%mod;
}
FWT_xor_2(0,p);
for (int i=1;i<=p;i++) ans=(ans+a[i])%mod;
cout<<ans<<endl;
return 0;
}
标签:Atcoder,212,gcd,int,题解,mid,FWT,xor,mod 来源: https://blog.csdn.net/Cherrt/article/details/119291113