洛谷P2000 题解

  • 生成函数模板题

首先对于要求为 k k k 倍数的要求可以构造生成函数: ( 1 + x k + x 2 k + . . . + x n k ) (1+x^k+x^{2k}+...+x^{nk}) (1+xk+x2k+...+xnk)

由定理可得: ( 1 + x k + x 2 k + . . . + x n k ) = 1 1 − x k (1+x^k+x^{2k}+...+x^{nk})=\frac{1}{1-x^k} (1+xk+x2k+...+xnk)=1xk1

对于另一种要求及 ( ∑ i = 0 k x i ) = 1 − x k + 1 1 − x (\sum_{i=0}^{k} x^i)=\frac{1-x^{k+1}}{1-x} (i=0kxi)=1x1xk+1

然后我们把这些项全部乘起来得: f ( x ) = ( 1 + x + x 1 + x 2 + . . ) 5 f(x)=(1+x+x^1+x^2+..)^5 f(x)=(1+x+x1+x2+..)5

答案就是上面这个多项式 x n x^n xn 的系数之和: A n s = ( n + 1 ) ( n + 2 ) ( n + 3 ) ( n + 4 ) 24 Ans=\frac{(n+1)(n+2)(n+3)(n+4)}{24} Ans=24(n+1)(n+2)(n+3)(n+4)

由于 n = 1 0 5 n=10^5 n=105以及优秀的模数直接用 N T T NTT NTT计算即可

  • C o d e Code Code
#include  
#define int long long
#define For(i,a,b) for ( register int i=(a);i<=(b);i++ )
#define Dow(i,b,a) for ( int i=(b);i>=(a);i-- )
#define GO(i,x) for ( int i=head[x];i;i=e[i].nex )
#define mem(x,s) memset(x,s,sizeof(x))
#define cpy(x,s) memcpy(x,s,sizeof(x))
#define YES return puts("YES"),0
#define NO return puts("NO"),0
#define GG return puts("-1"),0
#define pb push_back

using namespace std;

inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

const int N=6e5+5;
const int mo=998244353;
const int G=3;

int n,m,l1,l2,l3,l4,a[N],b[N],c[N],d[N],ans[N];
int r[N],lim=1,II=0;
char s[N];

inline int ksm(int x,int y)
{
	int ret=1;
	while(y)
	{
		if(y&1ll) ret=ret*x%mo;
		x=x*x%mo;
		y>>=1ll;
	}
	return ret%mo;
}

inline void NTT(int *a,int inv)
{
	
	For(i,0,lim-1) if(i<r[i]) swap(a[i],a[r[i]]);
	for ( register int mid=1;mid<lim;mid<<=1ll)
	{
		int tmp=ksm(G,(mo-1)/(mid*2ll));
		if(inv) tmp=ksm(tmp,mo-2);
		for ( register int i=0;i<lim;i+=mid*2ll )
		{
			int w=1ll;
			for ( register int j=0;j<mid;j++,w=w*tmp%mo )
			{
				int x=a[i+j];
				int y=w*a[i+j+mid]%mo;
				a[i+j]=(x+y)%mo;
				a[i+j+mid]=(x-y+mo)%mo;
			}
		}
	}
	if(inv) 
		For(i,0,lim-1) a[i]=a[i]*II%mo;
}

inline void MUL(int *f,int *g)
{
	NTT(f,0),NTT(g,0);
//	puts("orz");
	For(i,0,lim-1) f[i]=f[i]*g[i]%mo;
	NTT(f,1);
	int tmp=0;
	For(i,0,lim-1) 
	{
		a[i]+=tmp;
		tmp=a[i]/10ll;
		a[i]%=10ll;
		if(a[i]) l1=i+1;
	}
}

signed main()
{
//	freopen("A.in","r",stdin);
//	freopen("A.out","w",stdout);
	scanf("%s",s);
	int len=strlen(s);
	int l=0;
	lim=1ll;
	while(lim<=400000) lim<<=1ll,l++;
	II=ksm(lim,mo-2);
	For(i,0,lim-1) r[i]=r[i>>1ll]>>1ll|((i&1ll)<<(l-1));
	reverse(s,s+len);
	For(i,0,len-1) a[i]=s[i]-48;
	int x=1;
	
	For(i,0,len)
	{
		a[i]=a[i]+x;
		x=a[i]/10ll;
		a[i]%=10ll;
		if(a[i]) l1=i+1;
	}
	x=1;
	For(i,0,l1-1)
	{
		b[i]=a[i]+x;
		x=b[i]/10ll;
		b[i]%=10ll;
		if(b[i]) l2=i+1;
	}
	x=1;
	For(i,0,l2-1)
	{
		c[i]=b[i]+x;
		x=c[i]/10ll;
		c[i]%=10ll;
		if(c[i]) l3=i+1;
	}
	x=1;
	For(i,0,l3-1)
	{
		d[i]=c[i]+x;
		x=d[i]/10ll;
		d[i]%=10ll;
		if(d[i]) l4=i+1;
	}
	MUL(a,b);
	MUL(a,c);
	MUL(a,d);
	int P=0,ll=0;
	Dow(i,l1-1,0)
	{
		P=P*10ll+a[i];
		ans[i]=P/24ll;
		P%=24ll;
		if(ans[i]&&!ll) ll=i+1;
	}
	if(!ll) ll=1;
	Dow(i,ll-1,0) printf("%lld",ans[i]);
	return 0;
}
	
		

你可能感兴趣的:(多项式,fft,数论)