链接
单位根反演
其实就是一个公式,学过 F F T FFT FFT的人都能很容易的理解:
[ n ∣ k ] = 1 n ∑ i = 0 n − 1 ω n i k [n|k] = \frac{1}{n} \sum_{i=0}^{n-1} \omega_n^{ik} [n∣k]=n1i=0∑n−1ωnik
证明很简单,当
n
∣
k
n|k
n∣k时
n
∣
i
k
n|ik
n∣ik,所以
ω
n
i
k
=
ω
n
0
=
1
\omega_{n}^{ik} = \omega_n^0 = 1
ωnik=ωn0=1,那么右边就等于
1
1
1
否则,就是一个等比数列求和,
w
n
0
−
w
n
n
k
1
−
w
n
k
=
0
\frac{w_{n}^{0}-w_n^{nk}}{1-w_n^k} = 0
1−wnkwn0−wnnk=0,右边等于
0
0
0
题解
根据 ( n i ) = ( n n − i ) \binom{n}{i}=\binom{n}{n-i} (in)=(n−in),以及异或运算的性质,可以得到以下结论:
当 n n n为奇数的时候, a n s = 0 ans=0 ans=0
当 n n n为偶数的时候, a n s = a n s ( n / 2 m o d k ) ∧ a n s ( ( n / 2 + k / 2 ) m o d k ) ans = ans_{(n/2 \mod k)} \wedge ans_{ ((n/2+k/2) \mod k)} ans=ans(n/2modk)∧ans((n/2+k/2)modk)
其中 ∧ \wedge ∧表示异或
所以现在需要解决的问题就是对于某个给定的 t t t,求出 a n s t ans_t anst
直接硬写:
∑ i = − t n − t ( n i + t ) [ k ∣ i ] = ∑ i = − t n − t ( n i + t ) ∑ j = 0 k − 1 ω k i j = ∑ j = 0 k − 1 ∑ i = − t n − t ( n i + t ) ω k i j \sum_{i=-t}^{n-t} \binom{n}{i+t} [k|i] \\ = \sum_{i=-t}^{n-t} \binom{n}{i+t} \sum_{j=0}^{k-1} \omega_{k}^{ij} \\ = \sum_{j=0}^{k-1} \sum_{i=-t}^{n-t} \binom{n}{i+t} \omega_{k}^{ij} i=−t∑n−t(i+tn)[k∣i]=i=−t∑n−t(i+tn)j=0∑k−1ωkij=j=0∑k−1i=−t∑n−t(i+tn)ωkij
令 p = i + t p=i+t p=i+t
∑ j = 0 k − 1 ∑ p = 0 n ( n p ) ω k j ( p − t ) = ∑ j = 0 k − 1 ω k − j t ∑ p = 0 n ( n p ) ( ω k j ) p = ∑ j = 0 k − 1 ω k − j t ( 1 + ω k j ) n \sum_{j=0}^{k-1} \sum_{p=0}^n \binom{n}{p} \omega_{k}^{j(p-t)} \\ = \sum_{j=0}^{k-1} \omega_{k}^{-jt} \sum_{p=0}^n \binom{n}{p} (\omega_{k}^{j})^p \\ = \sum_{j=0}^{k-1} \omega_k^{-jt} (1+\omega_{k}^{j} )^n j=0∑k−1p=0∑n(pn)ωkj(p−t)=j=0∑k−1ωk−jtp=0∑n(pn)(ωkj)p=j=0∑k−1ωk−jt(1+ωkj)n
所以直接枚举 j j j然后快速幂就行了
代码
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 1500000
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
#define mod 998244353ll
ll n, k, wk[maxn];
ll fastpow(ll a, ll b)
{
ll t(a%mod), ans(1);
b=(b%(mod-1)+(mod-1))%(mod-1);
for(;b;b>>=1,t=t*t%mod)if(b&1)(ans*=t)%=mod;
return ans;
}
void pre()
{
ll i;
wk[0]=1, wk[1]=fastpow(3,(mod-1)/k);
rep(i,2,k-1)wk[i]=wk[i-1]*wk[1]%mod;
}
ll calc(ll t)
{
ll i, j, ans=0, mi=1, wkt=fastpow(wk[1],-t);
rep(j,0,k-1)
{
ll tmp=mi*fastpow(1+wk[j],n)%mod;
(ans+=tmp)%=mod;
mi=mi*wkt%mod;
}
ans=ans*fastpow(k,mod-2)%mod;
return (ans+mod)%mod;
}
char s[maxn];
ll tmp[maxn];
int main()
{
ll i, j, len, t1=0, t2;
scanf("%s%lld",s,&k); len=strlen(s);
rep(i,0,len-1)(n=n*10+s[i]-0x30)%=(mod-1);
if(s[len-1]%2==1){printf("0"); return 0;}
if(k==1){printf("%lld",fastpow(2,n)); return 0;}
rep(i,0,len-1)tmp[i]=s[i]-0x30;
rep(i,0,len-1)
{
tmp[i+1]+=tmp[i]%2*10;
tmp[i]/=2;
t1=(t1*10+tmp[i])%k;
}
t2=(t1+k/2)%k;
pre();
printf("%lld",calc(t1)^calc(t2));
return 0;
}