【dp,数学】CF1096G Lucky Tickets

我,常数,大。

考虑记给出的可用集合为 \(a\),令 \(f[i][j]\) 为选 \(i\) 个数和为 \(j\) 的方案,则 \(ans=\sum_{i=0}^{5n}f[n/2][i]^2\)

转移:\(f[i][j]=\sum f[i-1][j-x],x\in a\)

考虑记 \(g[x]=[x\in a]\)

那么,\(f[i][j]=\sum f[i-1][j-x]*g[x]\)

这东西是个卷积的形式,则每次用 NTT 做即可。考虑一共做 \(\dfrac{n}{2}\) 次,则变成多项式快速幂问题。

这里写的是 2log 的倍增,把 #define int long long 去掉后能大大减小常数。

#include <bits/stdc++.h>
using namespace std;
int rd() {
    int f=1,sum=0; char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return sum*f;
}
void pr(int x) {
	int f=1,tot=0; static int st[30];
	if(x<0) x=-x,f=-1;
	while(x) st[++tot]=x%10,x/=10;
	if(!tot) putchar('0');
	else for(int i=tot;i>=1;i--) putchar(st[i]+'0');
}

const int mod=998244353,G=3,INVG=332748118;
int fpow(int x,int y) {
	int res=1; x%=mod;
	while(y) {
		if(y&1) res=res*1ll*x%mod;
		y>>=1; x=x*1ll*x%mod;
	}
	return res;
}
#define N (int)(2e5+5) 
int tr[N<<4];
inline void NTT(vector<int>&f,int n,bool fl) {
	for(int i=0;i<n;i++) if(i<tr[i]) swap(f[i],f[tr[i]]);
	for(int p=2;p<=n;p<<=1) {
		int len=(p>>1),w=fpow(fl?G:INVG,(mod-1)/p);
		for(int l=0;l<n;l+=p) {
			int buf=1;
			for(int i=l;i<l+len;i++) {
				int qwq=f[i+len]*1ll*buf%mod;
				f[i+len]=((f[i]-qwq)%mod+mod)%mod;
				f[i]=(f[i]+qwq)%mod;
				buf=buf*1ll*w%mod;
			}
		}
	}
	if(fl) return ;
	int qwq=fpow(n,mod-2);
	for(int i=0;i<n;i++) f[i]=f[i]*1ll*qwq%mod;
}

inline vector<int> operator *(vector<int>f,vector<int>g) {
	int lef=f.size(),leg=g.size(); int m=1;
	while(m<lef+leg-1) m<<=1;
	for(int i=0;i<m;i++) tr[i]=(tr[i>>1]>>1)|((i&1)?(m>>1):0);
	f.resize(m); g.resize(m);
	NTT(f,m,1); NTT(g,m,1);
	for(int i=0;i<m;i++) f[i]=f[i]*1ll*g[i]%mod;
	NTT(f,m,0); f.resize(lef+leg-1);
	return f; 
}

inline vector<int> qpow(vector<int>f,int y) {
	vector<int>res; res.resize(1);
	res[0]=1;
	while(y>0) {
		if(y&1) res=res*f;
		y>>=1; f=f*f;
	}
	return res;
}
vector<int>f(10); 
signed main() {	
	int n=rd(),m=rd();
	for(int i=0;i<10;i++) f[i]=0;
	for(int i=1;i<=m;i++) {
		int x=rd(); f[x]=1;
	}
	f=qpow(f,n/2);
	int ans=0;
	for(int x:f) ans=(ans+x*1ll*x%mod)%mod;
	cout<<ans;
	return 0;
}
posted @ 2022-02-08 18:04  FxorG  阅读(29)  评论(0编辑  收藏  举报