P2000 拯救世界
题意:
- 10 10 10 种用混沌之石的方法生成大阵,求 n n n 块神石能生成的大阵数量
分析:
- 生成函数板子题 + + + 快速高精乘( N T T NTT NTT 优化)
- 下面列出十种神石的生成函数
-
f ( x ) = 1 + x 6 + x 12 + x 18 + . . . = 1 1 − x 6 f(x)=1+x^6+x^{12}+x^{18}+...=\frac{1}{1-x^6} f(x)=1+x6+x12+x18+...=1−x61
-
f ( x ) = 1 + x + x 2 + x 3 + . . . + x 9 = 1 − x 10 1 − x f(x)=1+x+x^2+x^3+...+x^9=\frac{1-x^{10}}{1-x} f(x)=1+x+x2+x3+...+x9=1−x1−x10
-
f ( x ) = 1 + x + x 2 + x 3 + . . . + x 5 = 1 − x 6 1 − x f(x)=1+x+x^2+x^3+...+x^5=\frac{1-x^{6}}{1-x} f(x)=1+x+x2+x3+...+x5=1−x1−x6
-
f ( x ) = 1 + x 4 + x 8 + x 12 + . . . = 1 1 − x 4 f(x)=1+x^4+x^8+x^{12}+...=\frac{1}{1-x^4} f(x)=1+x4+x8+x12+...=1−x41
-
f ( x ) = 1 + x + x 2 + x 3 + . . . + x 7 = 1 − x 8 1 − x f(x)=1+x+x^2+x^3+...+x^7=\frac{1-x^{8}}{1-x} f(x)=1+x+x2+x3+...+x7=1−x1−x8
-
f ( x ) = 1 + x 2 + x 4 + x 6 + . . . = 1 1 − x 2 f(x)=1+x^2+x^4+x^6+...=\frac{1}{1-x^2} f(x)=1+x2+x4+x6+...=1−x21
-
f ( x ) = 1 + x = 1 − x 2 1 − x f(x)=1+x=\frac{1-x^2}{1-x} f(x)=1+x=1−x1−x2
-
f ( x ) = 1 + x 8 + x 16 + x 24 + . . . = 1 1 − x 8 f(x)=1+x^8+x^{16}+x^{24}+...=\frac{1}{1-x^8} f(x)=1+x8+x16+x24+...=1−x81
-
f ( x ) = 1 + x 10 + x 20 + x 30 + . . . = 1 1 − x 10 f(x)=1+x^{10}+x^{20}+x^{30}+...=\frac{1}{1-x^{10}} f(x)=1+x10+x20+x30+...=1−x101
-
f ( x ) = 1 + x + x 2 + x 3 = 1 − x 4 1 − x f(x)=1+x+x^2+x^3=\frac{1-x^{4}}{1-x} f(x)=1+x+x2+x3=1−x1−x4
10 10 10 个式子相乘得到总的生成函数:
( 1 − x 10 ) ( 1 − x 6 ) ( 1 − x 8 ) ( 1 − x 2 ) ( 1 − x 4 ) ( 1 − x 6 ) ( 1 − x ) 5 ( 1 − x 4 ) ( 1 − x 2 ) ( 1 − x 8 ) ( 1 − x 10 ) = ( 1 − x ) − 5 \frac{(1-x^{10})(1-x^{6})(1-x^{8})(1-x^{2})(1-x^{4})}{(1-x^{6})(1-x^{})^5(1-x^{4})(1-x^{2})(1-x^{8})(1-x^{10})}=(1-x)^{-5} (1−x6)(1−x)5(1−x4)(1−x2)(1−x8)(1−x10)(1−x10)(1−x6)(1−x8)(1−x2)(1−x4)=(1−x)−5
再根据牛顿广义二项式定理:( 1 − x ) − n = ∑ i = 0 ∞ ( i n + i − 1 ) x i (1-x)^{-n} = \sum^{\infty}_{i=0}(^{n+i-1}_i)x^i (1−x)−n=i=0∑∞(in+i−1)xi
答案即为: ( 4 n + 4 ) = ( n + 4 ) ( n + 3 ) ( n + 2 ) ( n + 1 ) 24 (^{n+4}_4)=\frac{(n+4)(n+3)(n+2)(n+1)}{24} (4n+4)=24(n+4)(n+3)(n+2)(n+1)用 N T T NTT NTT 加速高精乘计算即可
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = (1<<22)+5, mo=998244353;
int rev[N];
void init(int k)
{
int s=1<<k;
for(int i=1;i<s;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
}
int binpow(int a,int b)
{
int ans=1;
while(b)
{
if(b&1) ans = ans*a%mo;
a = a*a%mo;
b >>= 1;
}
return ans;
}
void ntt(int *a, int n, int inv)
{
for(int i=0;i<n;i++)
{
if(i < rev[i]) swap(a[i], a[rev[i]]);
}
for(int len=1;len<n;len<<=1)
{
int Wn = binpow(3, (mo-1)/(len<<1));
if(inv == -1) Wn = binpow(Wn, mo-2);
for(int i=0;i<n;i+=(len<< 1))
{
int w=1;
for(int j=0;j<len;j++, w = (w*Wn)%mo)
{
int x = a[i + j], y = w*a[i+j+len]%mo;
a[i+j] = (x+y)%mo; a[i+j+len] = (x-y+mo)%mo;
}
}
}
if(inv == -1)
{
int fg=binpow(n, mo-2);
for(int i=0;i<n;i++) a[i] = a[i]*fg%mo;
}
}
void pre(int *a,int *b,int &n,int m)
{
int s=2, k=1;
while(s < n+m-1) k++, s <<= 1;
init(k);
ntt(a,s,1); ntt(b,s,1);
for(int i=0;i<s;i++) a[i] *= b[i];
ntt(a,s,-1); ntt(b,s,-1);
for(int i=0;i<s;i++)
{
a[i+1] += a[i]/10;
a[i] %= 10;
}
while(!a[s] && s>-1) s--;
n = s+1;
}
int a[N], b[N];
char s[N];
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
cin>>s;
int n=strlen(s);
for(int i=0;i<n;i++) a[i] = b[i] = s[n-i-1]-'0';
a[0]++; b[0]++;
int la=n, lb=n;
for(int i=1;i<4;i++)
{
b[0]++;
pre(a,b,la,lb);
}
int fg=0;
for(int i=la-1;i>=0;i--)
{
if(i) a[i-1] += (a[i]%24)*10;
a[i] /= 24;
if(a[i] || fg) fg=1, cout<<a[i];
}
return 0;
}