CF1096G Lucky Tickets [FFT/NTT]

题意

一个$n$位数,每位可以是给出的$k$个数码中的一个数,可以有前导$0$,输出前$n/2$位之和与后$n/2$位之和相等的方案数,保证$n$是偶数。

输入的第一行是两个整数$n,k$,接下来的一行有$k$个数$d_1,d_2,\cdots,d_k(0\leq d_i\leq 9)$

输出一个数,为方案数模$998244353$的值。


求出用$n/2$位的数得到的和的方案数$f[n]$,答案为$$\sum_{i=1}^{maxN}f[i]^{2}$$

将数字$k$视为多项式的一项$x^{k}$,得到$$F(x)=\sum_{i=0}^{9}a_{i}x^{i}$$ 其中$a_{i}$是$0$或$1$。

那么一共可以选择$n/2$位,$F(x)$的$n/2$次就是答案,可以点值后快速幂再插值。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 const int N=8000010;
 7 const ll P=998244353,g=3,gi=332748118;
 8 int n,m,K,fn,r[N],l,x,mw;
 9 ll ans,f[N],inv;
10 inline ll qpow(ll x,ll k) {ll r=1; for (; k; k>>=1ll,x=x*x%P) if (k&1ll) r=r*x%P; return r;}
11 inline void init(int n) {
12     for (fn=1,l=0; fn<=n; fn<<=1) ++l;
13     for (int i=0; i<fn; i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
14     inv=qpow((ll)fn,P-2ll);
15 }
16 void NTT(ll *c,ll t) {
17     for (int i=0; i<fn; i++) if (i<r[i]) swap(c[i],c[r[i]]);
18     for (int i=1; i<fn; i<<=1) {
19         ll Wn=qpow(t,(P-1ll)/(ll)(i<<1));
20         for (int j=0; j<fn; j+=(i<<1)) {
21             ll w=1;
22             for (int k=0; k<i; k++,w=w*Wn%P) {
23                 ll x=c[j+k],y=w*c[i+j+k]%P;
24                 c[j+k]=(x+y)%P; c[i+j+k]=(x+P-y)%P;
25             }
26         }
27     }
28 }
29 int main() {
30     scanf("%d%d",&n,&K); n>>=1;
31     while (K--) scanf("%d",&x),f[x]=1ll;
32     init(9*n);
33     NTT(f,g);
34     for (int i=0; i<fn; i++) f[i]=qpow(f[i],n);
35     NTT(f,gi);
36     for (int i=0; i<fn; i++) f[i]=f[i]*inv%P;
37     for (int i=0; i<=fn; i++) ans=(ans+f[i]*f[i]%P)%P;
38     printf("%lld\n",ans);
39     return 0;
40 }

 

posted @ 2019-01-02 14:04  HNOOO  阅读(276)  评论(0编辑  收藏  举报