luogu2000 拯救世界

题目链接

solution

该博文刚写完,就不小心手残清空了,只好重写。

生成函数练手题

先写上这个式子\(\frac{1}{1-x}=1+x+x^2+x^3+x^4+...\)

题目中描述了两种限制。

  • 第一种限制:神石的块数必须是\(t\)的倍数,那么他的生成函数就是\(1+x^t+x^{2t}+x^{3t}+...\)。这就相当于用\(x^t\)替换掉了上方式子中的\(x\)。所以该生成函数就是\(\frac{1}{1-x^t}\)

  • 第二中限制:神石的数目不超过\(t\),那么他的生成函数就是\(1+x+x^2+x^3+...+x^t\)。我们将其看作\((1+x+x^2+x^3+...)-(x^{t+1}+x^{t+2}+x^{t+3}+...)\)。第一个括号里的内容就是\(\frac{1}{1-x}\),第二个括号里就相当于将最上方的式子每项都乘以\(x^{t+1}\)。所以第二个括号里的内容就是\(\frac{x^{t+1}}{1-x}\)。所以该限制的生成函数就是\(\frac{1-x^{t+1}}{1-x}\)

然后将所有的限制用生成函数描述出来,并相乘,所得多项式的第\(n\)项就是答案。

这10个限制的生成函数相乘为\(\frac{1}{1-x^6}\cdot\frac{1-x^{10}}{1-x}\cdot \frac{1-x^6}{1-x}\cdot\frac{1}{1-x^4}\cdot \frac{1-x^8}{1-x}\cdot\frac{1}{1-x^2}\cdot\frac{1-x^2}{1-x}\cdot\frac{1}{1-x^8}\cdot\frac{1}{1-x^{10}}\cdot\frac{1-x^4}{1-x}\)

约分一下发现就是\(\frac{1}{(1-x)^5}\)

由广义二项式定理\(\frac{1}{(1-x)^k}=\sum\limits_{n\ge0}C_{n+k-1}^nx^n\)

所以第n项的系数就是\(C_{n+4}^n=\frac{(n+1)(n+2)(n+3)(n+4)}{24}\)

n比较大,用NTT或者FFT优化高精乘即可。

code

/*
* @Author: wxyww
* @Date:   2020-04-16 09:31:03
* @Last Modified time: 2020-04-16 10:17:08
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 1000010,mod = 998244353;
ll read() {
	ll x = 0,f = 1;char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1; c = getchar();
	}
	while(c >= '0' && c <= '9') {
		x = x * 10 + c - '0'; c = getchar();
	}
	return x * f;
}
char s[N];
struct BIGNUM {
	int a[N],len;

	void Read() {
		scanf("%s",s);
		len = strlen(s);
		for(int i = 0;i < len;++i) a[i] = s[len - i - 1] - '0';
	}
}n,a1,a2,a3,a4;

BIGNUM operator + (BIGNUM A,int x) {
	A.a[0] += x;
	for(int i = 0;i < A.len;++i) {
		if(A.a[i] >= 10) {
			 A.a[i + 1] += A.a[i] / 10;
			 A.a[i] %= 10;
			 if(i == A.len - 1) ++A.len;
		}
	}
	return A;
}
BIGNUM operator / (BIGNUM A,int x) {
	int now = 0;
	for(int i = A.len - 1;i >= 0;--i) {
		now = now * 10 + A.a[i];
		A.a[i] = now / x;
		now %= x;
	}
	while(!A.a[A.len - 1]) --A.len;
	return A;
}
int qm(int x,int y) {
	int ret = 1;
	for(;y;y >>= 1,x = 1ll * x * x % mod)
		if(y & 1) ret = 1ll * ret * x % mod;
	return ret;
}
int rev[N];
void NTT(int *a,int n,int xs) {
	for(int i = 0;i <= n;++i) if(rev[i] > i) swap(a[i],a[rev[i]]);

	for(int m = 2;m <= n;m <<= 1) {
		ll w1 = qm(3,(mod - 1) / m);
		if(xs == -1) w1 = qm(w1,mod - 2);
		for(int i = 0;i < n;i += m) {
			ll w = 1;
			for(int k = 0;k < (m >> 1);++k) {
				ll u = a[i + k],t = w * a[i + k + (m >> 1)] % mod;
				a[i + k] = (u + t) % mod;a[i + k + (m >> 1)] = (u - t + mod) % mod;
				w = w * w1 % mod;
			}
		}
	}
}

int t1[N],t2[N];
BIGNUM operator * (const BIGNUM &A,const BIGNUM &B) {
	int len = A.len + B.len - 1;

	int tot = 1;
	while(tot <= len) tot <<= 1;

	// printf("!!!%d\n",tot);

	for(int i = 0;i <= tot;++i)
		rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? (tot >> 1) : 0);

	memset(t1,0,sizeof(t1));memset(t2,0,sizeof(t2));

	for(int i = 0;i < A.len;++i) t1[i] = A.a[i];
	for(int i = 0;i < B.len;++i) t2[i] = B.a[i];

	// printf("%d\n",tot);

	NTT(t1,tot,1);NTT(t2,tot,1);

	
	
	for(int i = 0;i <= tot;++i) t1[i] = 1ll * t1[i] * t2[i] % mod;

	NTT(t1,tot,-1);

	// for(int i = 0;i <= tot;++i) printf("%d ",t1[i]);	puts("");
	int tmp = qm(tot,mod - 2);
	BIGNUM C;
	C.len = len;
	for(int i = 0;i <= tot;++i)
		t1[i] = 1ll * t1[i] * tmp % mod;
	for(int i = 0;i < C.len;++i) {
		if(t1[i] >= 10) {
			t1[i + 1] += t1[i] / 10;
			t1[i] %= 10;
			if(i == C.len - 1) ++C.len;
		}
			C.a[i] = t1[i];
			// printf("%d ",t1[i]);
	}
	// printf("%d%d\n",C.a[0],C.a[1]);
	// puts("");
	return C;
}

int main() {
	n.Read();
	// BIGNUM K = (n + 1) * (n + 2);
	BIGNUM K = (n + 1) * (n + 2) * (n + 3) * (n + 4) / 24;
	for(int i = K.len - 1;i >= 0;--i) printf("%d",K.a[i]);

	return 0;
}
posted @ 2020-04-16 11:09  wxyww  阅读(142)  评论(2编辑  收藏  举报