Problem
BZOJ
竟然是HN省队集训的题,出题人还贴心地把模数改成了
998244353
998244353
998244353,好感动,我还以为HN省队集训都是一堆毒瘤出自己都不会/想做的题。
原题应该是这个,只不过原题要MTT:Codeforces623E Transforming Sequence
Solution
首先 n n n 的范围是假的,因为要严格递增,每次 b i b_i bi 至少会有1位由0变成1,因此 n > k n>k n>k 时答案为0。
设
f
[
n
]
[
i
]
f[n][i]
f[n][i] 表示前
n
n
n 个数的或和用了
i
i
i 位的方案数,那么
f
[
n
]
[
i
]
=
∑
j
=
1
i
f
[
n
−
1
]
[
i
−
j
]
(
i
j
)
2
i
−
j
f[n][i]=\sum_{j=1}^i f[n-1][i-j]\binom {i} {j}2^{i-j}
f[n][i]=j=1∑if[n−1][i−j](ji)2i−j
但这样还是太慢了,注意到转移关系和第一维其实没有关系,那么不妨考虑能不能一次合并多个数
f
[
x
+
y
]
[
i
]
=
∑
j
=
1
i
f
[
x
]
[
j
]
(
i
j
)
f
[
y
]
[
i
−
j
]
2
j
y
=
i
!
∑
j
=
0
i
f
[
x
]
[
j
]
2
j
y
j
!
⋅
f
[
y
]
[
i
−
j
]
(
i
−
j
)
!
f[x+y][i]=\sum_{j=1}^i f[x][j]\binom i j f[y][i-j] 2^{jy}=i!\sum_{j=0}^i \frac {f[x][j]2^{jy}} {j!}\cdot\frac {f[y][i-j]} {(i-j)!}
f[x+y][i]=j=1∑if[x][j](ji)f[y][i−j]2jy=i!j=0∑ij!f[x][j]2jy⋅(i−j)!f[y][i−j]
DP快速幂+NTT优化卷积即可,最后的答案为 ∑ i f [ n ] [ i ] ( k i ) \sum_{i} f[n][i] \binom k i ∑if[n][i](ik)
时间复杂度 O ( k log 2 k ) O(k\log^2 k) O(klog2k)。
Code
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=150010,mod=998244353,G=3;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
int k,N,l,ans,rev[maxn],mi[maxn],fac[maxn],inv[maxn],res[maxn],tmp[maxn];
ll n;
int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int dec(int x,int y){return x<y?x-y+mod:x-y;}
int C(int n,int m){return m>n?0:(ll)fac[n]*inv[m]%mod*inv[n-m]%mod;}
int power(int x,ll y)
{
int res=1;
for(;y;y>>=1,x=(ll)x*x%mod)
if(y&1)
res=(ll)res*x%mod;
return res;
}
void NTT(int *a,int f)
{
for(int i=1;i<N;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int i=1;i<N;i<<=1)
{
int gn=power(G,(mod-1)/(i<<1));
for(int j=0;j<N;j+=(i<<1))
{
int g=1,x,y;
for(int k=0;k<i;++k,g=(ll)g*gn%mod)
{
x=a[j+k];y=(ll)a[j+k+i]*g%mod;
a[j+k]=pls(x,y);a[j+k+i]=dec(x,y);
}
}
}
if(f==-1)
{
int iv=power(N,mod-2);reverse(a+1,a+N);
for(int i=0;i<N;i++) a[i]=(ll)a[i]*iv%mod;
}
}
void mul(int x,int y,int *fx,int *fy,int *c)
{
static int a[maxn],b[maxn];
for(int i=0;i<=k;i++) a[i]=(ll)fx[i]*power(2,(ll)i*y)%mod*inv[i]%mod;
for(int i=0;i<=k;i++) b[i]=(ll)fy[i]*inv[i]%mod;
for(int i=k+1;i<N;i++) a[i]=b[i]=0;
NTT(a,1);NTT(b,1);
for(int i=0;i<N;i++) a[i]=(ll)a[i]*b[i]%mod;
NTT(a,-1);
for(int i=0;i<=k;i++) c[i]=(ll)a[i]*fac[i]%mod;
}
int main()
{
read(n);read(k);fac[0]=mi[0]=1;
if(n>k){puts("0");return 0;}
for(int i=1;i<=k;i++) fac[i]=(ll)fac[i-1]*i%mod,mi[i]=pls(mi[i-1],mi[i-1]);
inv[k]=power(fac[k],mod-2);
for(int i=k-1;~i;i--) inv[i]=(ll)inv[i+1]*(i+1)%mod;
for(N=1,l=0;N<=(k<<1);N<<=1) ++l;
for(int i=1;i<N;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
for(int i=1;i<=k;i++) res[i]=tmp[i]=1;
--n;
for(int i=1,j=1;i<=n;i<<=1,j+=i&n)
{
if(n&i) mul(j,i,res,tmp,res);
mul(i,i,tmp,tmp,tmp);
}
for(int i=0;i<=k;i++) ans=(ans+(ll)res[i]*C(k,i))%mod;
printf("%d\n",ans);
return 0;
}