洛谷P2000题解

题目传送门

题目:

题目背景

公元 2000 年,根据预言家诺查丹玛斯的预言,世界就要毁灭了!!!

题目描述

为了拯救世界,小 a 和 uim 决定召唤出 kkksc03 大神和 lzn 大神。根据古籍记载,召唤出任何一位大神,都需要使用金木水火土五种五行神石来摆一个特定的大阵。而在古籍中,记载是这样的:

kkksc03 大神召唤方法:

  • 金神石的块数必须是6的倍数;
  • 木神石最多用9块;
  • 水神石最多用5块;
  • 火神石的块数必须是4的倍数;
  • 土神石最多用7块。

lzn 大神召唤方法:

  • 金神石的块数必须是2的倍数;
  • 木神石最多用1块;
  • 水神石的块数必须是8的倍数;
  • 火神石的块数必须是10的倍数;
  • 土神石最多用 33 块。

现在是公元 1999 年 12 月 31 日,小 a 和 uim 从00:00:00开始找,一直找到 23:0:00,终于,还是没找到神石。

不过,他们在回到家后在自家地窖里发现了一些奇怪的东西,一查古籍,哎呦妈呀,怎么不早点来呢?这里有一些混沌之石,可以通过敲击而衰变成五行神石。于是,他们拼命地敲,终于敲出了n块神石在23:59:59完成了两座大阵。

然而,kkksc03 大神和 lzn 大神确实出现了,但是由于能量不够,无法发挥神力。只有把所有用 n 块神石可能摆出的大阵都摆出来,才能给他们充满能量。这下小 a 和 uim 傻了眼了,赶快联系上了你,让你帮忙算一下,一共有多少种大阵。

输出格式
输入一个正整数 n。

输出格式

输出用 n 块混沌之石能摆出的大阵的种数。

输入输出样例

输入 #1

2

 输出#2

15

说明/提示

数据范围及约定

对于全部数据,10^{99999}\leq n<10^{100000}

提示

由于现在已经是 23:59:59,所以你只有 0.5 秒时间。(小 a 与 uim 需要 0.5s 排出所有阵法)。

题解

kkk牛逼!

本蒟蒻的BUG

生成函数裸题。

依次来看召唤每一位大神所需的每种石头的情况:

金神石的块数必须是6的倍数:1+x^{6}+x^{12}...=\frac{1}{1-x^{6}}

木神石最多用9块:1+x+x^2+...+x^9=\frac{1-x^{10}}{1-x}

水神石最多用5块:1+x^2+...+x^5=\frac{1-x^{6}}{1-x}

火神石的块数必须是4的倍数:1+x^4+x^8+...=\frac{1}{1-x^{4}}

土神石最多用7块:1+x+x^2+...+x^7=\frac{1-x^{8}}{1-x}

金神石的块数必须是2的倍数:1+x^2+x^4+···=\frac{1}{1-x^2}

木神石最多用1块:1+x=\frac{1-x^2}{1-x}

水神石的块数必须是8的倍数:1+x^8+x^{16}+...=\frac{1}{1-x^8}

火神石的块数必须是10的倍数:1+x^{10}+x^{20}+...=\frac{1}{1-x^10}

土神石最多用3块:1+x+x^2+x^3=\frac{1-x^4}{1-x}

然后把他们全部乘起来,就有:

                 \frac{1}{1-x^6}\frac{1-x^{10}}{1-x}·\frac{1-x^6}{1-x}·\frac{1}{1-x^4}·\frac{1-x^8}{1-x}·\frac{1}{1-x^2}·\frac{1-x^2}{1-x}·\frac{1}{1-x^8}·\frac{1}{1-x^{10}}·\frac{1-x^4}{1-x}

                                                    =(\frac{1}{1-x})^5

然后再把这个式子展开,就是:

                                            (1+x+x^2+x^3+...)^5

答案就是上面这个多项式x^n项前面的系数。

通过隔板法可以求出答案为(\frac{n+5-1}{5-1})=\frac{n(n+1)(n+2)(n+3)}{24}

由于数据范围很大,所以上NTT来优化高精度乘法即可。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int TT=998244353;
int r[263000];char n[100005];
inline int read()
{
	int ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
	return ret*f;
}
inline int QP(int a,int b)
{
	int ret=1,w=a;
	while(b)
	{
		if(b&1) ret=(LL)ret*w%TT;
		w=(LL)w*w%TT;b>>=1;
	}
	return ret;
}
inline void NTT(int* A,int limit,int type)
{
	for(int i=0;i<limit;i++)
		if(i<r[i])
			swap(A[i],A[r[i]]);
	for(int mid=1;mid<limit;mid<<=1)
	{
		int gn=QP(3,(TT-1)/(mid<<1));
		if(type<0) gn=QP(gn,TT-2);
		for(int j=0;j<limit;j+=mid<<1)
		{
			int g=1;
			for(int k=0;k<mid;k++,g=(LL)g*gn%TT)
			{
				int x=A[j+k],y=(LL)g*A[j+k+mid]%TT;
				A[j+k]=(x+y)%TT;
				A[j+k+mid]=(x-y+TT)%TT;
			}
		}
	}
	if(type<0)
	{
		int inv=QP(limit,TT-2);
		for(int i=0;i<=limit;i++) A[i]=(LL)A[i]*inv%TT;
	}
}
struct BigInteger
{
	int len,a[263000];
	BigInteger(){len=0;memset(a,0,sizeof(a));}
	BigInteger(char* S)
	{
		len=0;memset(a,0,sizeof(a));
		int n=strlen(S+1);
		reverse(S+1,S+1+n);
		len=(n+1)/2;
		for(int i=1;i<=n;i++) S[i]-='0';
		for(int i=1;i<=len;i++)
			a[i]=S[i*2-1]+S[i*2]*10;
	}
	BigInteger operator * (BigInteger b)
	{
		BigInteger a=*this,c;
		c.len=a.len+b.len;
		int limit=1,l=0;
		while(limit<=c.len){limit<<=1;l++;}
		for(int i=0;i<limit;i++)
			r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
		NTT(a.a+1,limit,1);
		NTT(b.a+1,limit,1);
		for(int i=1;i<=limit;i++)
			c.a[i]=(LL)a.a[i]*b.a[i]%TT;
		NTT(c.a+1,limit,-1);
		for(int i=1;i<=c.len;i++)
		{
			c.a[i+1]+=c.a[i]/100;
			c.a[i]%=100;
		}
		if(!c.a[c.len]) c.len--;
		return c;
	}
	void operator /= (int b)
	{
		for(int i=len;i;i--)
		{
			a[i-1]+=(a[i]%b)*100;
			a[i]/=b;
		}
		a[0]=0;
		if(!a[len]) len--;
	}
	inline void Inc()
	{
		a[1]++;
		for(int i=1;i<=len;i++)
		{
			if(a[i]<100) break;
			a[i+1]+=a[i]/100;
			a[i]%=100;
		}
		if(a[len+1]) len++;
	}
	void Print()
	{
		printf("%d",a[len]);
		for(int i=len-1;i>0;i--)
			printf("%02d",a[i]);
		putchar('\n');
	}
}A,B,C,D,ans;
int main()
{
	scanf("%s",n+1);
	A=n;A.Inc();
	B=A;B.Inc();
	C=B;C.Inc();
	D=C;C.Inc();
	ans=A*B*C*D;
	ans/=24;
	ans.Print();
	return 0;
}

以上的题目和公式都是博主手打的(时间:三天三夜),看在博主这么辛苦的份上给个点赞加关注吧,求求了!!!

另外,由于博主时间不够,格式可能不太好看,后续会慢慢优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值