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∑m​gcd(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∑m​F(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;
}
上一篇:Android零基础入门第60节:日历视图CalendarView和定时器Chronometer


下一篇:Java实现金字塔:1 212 32123 4321234 543212345.....