题目链接
这题还是蛮不错的,去年noip之前就推出了通项,但因为FFT被卡了精度就一直没写
和那道食物差不多的推式子方法
kkksc03大神召唤方法:
金神石的块数必须是6的倍数。
1
+
x
6
+
x
12
+
.
.
.
=
1
x
6
−
1
1+x^6+x^{12}+...=\frac{1}{x^6-1}
1+x6+x12+...=x6−11
木神石最多用9块。
1
+
x
+
x
2
+
.
.
.
+
x
9
=
x
10
−
1
x
−
1
1+x+x^2+...+x^9=\frac{x^{10}-1}{x-1}
1+x+x2+...+x9=x−1x10−1
水神石最多用5块。
x
6
−
1
x
−
1
\frac{x^6-1}{x-1}
x−1x6−1
火神石的块数必须是4的倍数。
1
x
4
−
1
\frac{1}{x^4-1}
x4−11
土神石最多用7块。
x
8
−
1
x
−
1
\frac{x^8-1}{x-1}
x−1x8−1
lzn大神召唤方法:
金神石的块数必须是2的倍数。
1
x
2
−
1
\frac{1}{x^2-1}
x2−11
木神石最多用1块。
x
2
−
1
x
−
1
\frac{x^2-1}{x-1}
x−1x2−1
水神石的块数必须是8的倍数。
1
x
8
−
1
\frac{1}{x^8-1}
x8−11
火神石的块数必须是10的倍数。
1
x
10
−
1
\frac{1}{x^{10}-1}
x10−11
土神石最多用3块。
x
4
−
1
x
−
1
\frac{x^4-1}{x-1}
x−1x4−1
反正一乘就会发现消掉了一堆,得到了
1
(
1
−
x
)
5
\frac{1}{(1-x)^5}
(1−x)51
广义二项式定理一下就是 c n + 5 − 1 5 − 1 = ( n + 1 ) ( n + 2 ) ( n + 3 ) ( n + 4 ) 24 c^{5-1}_{n+5-1}=\frac{(n+1)(n+2)(n+3)(n+4)}{24} cn+5−15−1=24(n+1)(n+2)(n+3)(n+4)
因为长度很长所以要高精度,用NTT搞下就可以了
代码如下:(一如既往的难看
#include<bits/stdc++.h>
#define mod 998244353
#define g 3ll
using namespace std;
char s[100010];
long long kasumi(long long a,long long b)
{
long long ans=1;
while(b)
{
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
long long n1[600040],n2[600040],n3[600040],n4[600040],ans[600040];
long long len1,len2,len3,len4;
long long limit=1,r[600040];
long long NTT(long long *a,long long kd)
{
for(long long i=0;i<limit;i++)
{
if(i<r[i])
{
swap(a[i],a[r[i]]);
}
}
for(long long mid=1;mid<limit;mid<<=1)
{
long long tmp=kasumi(g,(mod-1)/(mid*2));
if(kd) tmp=kasumi(tmp,mod-2);
for(long long i=0;i<limit;i+=mid*2)
{
long long w=1;
for(long long j=0;j<mid;j++,w=w*tmp%mod)
{
long long x=a[i+j];
long long y=w*a[i+j+mid]%mod;
a[i+j]=(x+y+mod)%mod;
a[i+j+mid]=(x-y+mod)%mod;
}
// cerr<<w<<endl;
}
}
if(kd)
{
long long inv=kasumi(limit,mod-2);
for(long long i=0;i<limit;i++)
{
a[i]=a[i]*inv%mod;
}
}
}
void mul(long long *a,long long *b)
{
NTT(a,0);
NTT(b,0);
for(long long i=0;i<limit;i++)
{
a[i]=a[i]*b[i]%mod;
}
NTT(a,1);
long long tmp=0;
for(long long i=0;i<limit;i++)
{
n1[i]+=tmp;
tmp=n1[i]/10;
n1[i]%=10;
if(n1[i]) len1=i+1;
}
}
int main()
{
long long ll=0;
scanf("%s",s);
long long len=strlen(s);
while(limit<=400000) limit<<=1,ll++;
for(int i=0;i<limit;i++)
{
r[i]=r[i>>1]>>1|((i&1)<<(ll-1));
}
reverse(s,s+len);
for(int i=0;i<len;i++)
{
n1[i]=s[i]-'0';
}
long long x=1;
for(int i=0;i<=len;i++)
{
n1[i]=n1[i]+x;
x=n1[i]/10;
n1[i]=n1[i]%10;
if(n1[i]) len1=i+1;
}
x=1;
for(int i=0;i<len1;i++)
{
n2[i]=n1[i]+x;
x=n2[i]/10;
n2[i]=n2[i]%10;
if(n2[i]) len2=i+1;
}
x=1;
for(int i=0;i<len2;i++)
{
n3[i]=n2[i]+x;
x=n3[i]/10;
n3[i]=n3[i]%10;
if(n3[i]) len3=i+1;
}
x=1;
for(int i=0;i<len3;i++)
{
n4[i]=n3[i]+x;
x=n4[i]/10;
n4[i]=n4[i]%10;
if(n4[i]) len4=i+1;
}
mul(n1,n2);
mul(n1,n3);
mul(n1,n4);
long long p=0,lenn=0;
for(int i=len1-1;i>=0;i--)
{
p=p*10+n1[i];
ans[i]=p/24;
p%=24;
if(ans[i]&&!lenn) lenn=i+1;
}
if(!lenn) lenn=1;
for(int i=lenn-1;i>=0;i--)
{
printf("%lld",ans[i]);
}
}