洛谷P4389 付公主的背包/loj #556. 「Antileaf's Round」咱们去烧菜吧

学了几天,总算是把loj这个题做出来了。。
随便开了一套题。。然后第一题就不会实在是太没有面子了
有挺多前置知识的
我的学习资料

两个题的题意基本都是一样的
只不过第一个比较简单,可以视为完全没有限制
第二个的话则是有限制的
很显然,第二个是第一个的加强版。。
当然两题都可以用第二个的做法来做
其实
从推导的难度来说,第二个做法简单一些
从知识的要求来说,第一个做法简单一些

首先,当然是先构造生成函数 1 + x + x a i + x 2 a 2 + . . . . . + x a i ∗ ( b i + 1 ) 1+x+x^{a_i}+x^{2a_2}+.....+x^{ai*(bi+1)} 1+x+xai+x2a2+.....+xai(bi+1)
最最暴力的方法就是直接一个一个式子NTT起来,那么复杂度就是 n m l o g m nmlogm nmlogm
乘起来不好做,于是考虑加起来
乘法什么时候可以变为加法呢?当然就是取对数的时候!
于是我们设一个函数 g ( x ) = l n ( f ( x ) ) g(x)=ln(f(x)) g(x)=ln(f(x))

第一个的话, b i b_i bi可以看做是无限
因此,可以写成 1 1 − x \frac{1}{1-x} 1x1
根据这个特殊的性质,我们可以对 g g g进行求导
可以得到 g ′ = f ′ ( x ) f ( x ) = ( 1 − x ) ( ∑ j ∗ a i ∗ x j ∗ a i − 1 ) g'=\frac{f'(x)}{f(x)}=(1-x)(\sum{j*a_i*x^{j*a_i-1}}) g=f(x)f(x)=(1x)(jaixjai1)
把式子展开,可以得到 g ′ = ∑ a i ∗ a j ∗ a i − 1 g'=\sum{a_i*a^{j*a_i-1}} g=aiajai1
再对 g ′ g' g进行积分,就可以得到 g = ∑ a i j ∗ a i x j ∗ a i = ∑ 1 j x j ∗ a i g=\sum{\frac{a_i}{j*a_i}x^{j*a_i}}=\sum{\frac{1}{j}x^{j*a_i}} g=jaiaixjai=j1xjai
容易发现,对于 a i a_i ai一样的,可以放在一起枚举倍数来对系数贡献
那么这个复杂度就是 O ( n l o g n ) O(nlogn) O(nlogn)
g求和以后,再EXP回去就好了

至于第二个,不可以写成 1 1 − x \frac{1}{1-x} 1x1的形式,于是积分完之后似乎没有上一个那么顺利,那么就只可以另辟捷径了,其实这个更简单一些
可以发现,他的式子是 1 − x a i ∗ ( b i + 1 ) 1 − x \frac{1-x^{a_i*(b_i+1)}}{1-x} 1x1xai(bi+1)
那么 g ( x ) = l n ( 1 − x a i ∗ ( b i + 1 ) ) − l n ( 1 − x ) g(x)=ln(1-x^{a_i*(b_i+1)})-ln(1-x) g(x)=ln(1xai(bi+1))ln(1x)
根据泰勒展开公式
l n ( 1 − x ) = − x − x 2 2 − x 3 3 − − x 4 4 − . . . . . . . . ln(1-x)=-x-\frac{x^2}{2}-\frac{x^3}{3}--\frac{x^4}{4}-........ ln(1x)=x2x23x34x4........
然后换元
l n ( 1 − x k ) = − x − x 2 k 2 − x 3 k 3 − − x 4 k 4 − . . . . . . . . ln(1-x^k)=-x-\frac{x^{2k}}{2}-\frac{x^{3k}}{3}--\frac{x^{4k}}{4}-........ ln(1xk)=x2x2k3x3k4x4k........
然后也是一样的枚举倍数就好了
最后EXP回去就行了

这里给出第二个代码
其实两个代码都差不多。。除了枚举倍数有一点点不同以外,剩下的都是板子问题
我们数学老师说,解析几何的秘诀就是一次算对
同样的,多项式的秘诀就是一次打对。。因为我根本不知道怎么调

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const LL N=100005*4;
const LL MOD=998244353,GG=3,GGI=332748118;
LL n,m;
LL t[N];
LL F[N],G[N];
LL A[N],B[N],C[N],D[N],E[N];
LL inv[N];
LL Pow (LL x,LL y)
{
	if (y==1) return x;
	LL lalal=Pow(x,y>>1);
	lalal=lalal*lalal%MOD;
	if (y&1) lalal=lalal*x%MOD;
	return lalal;
}
LL bin[N];
void NTT (LL *a,LL n,LL o)
{
	for (LL u=0;u<n;u++) bin[u]=(bin[u>>1]>>1)|((u&1)*(n>>1));
	for (LL u=0;u<n;u++)
		if (u<bin[u])
			swap(a[u],a[bin[u]]);
	for (LL u=1;u<n;u<<=1)
	{
		LL w,wn=Pow(o==1?GG:GGI,(MOD-1)/(u<<1)),t;
		for (LL i=0;i<n;i=i+(u<<1))
		{
			w=1;
			for (LL j=0;j<u;j++)
			{
				t=w*a[u+i+j]%MOD;
				a[u+i+j]=(a[i+j]-t+MOD)%MOD;
				a[i+j]=(a[i+j]+t)%MOD;
				w=w*wn%MOD;
			}
		}
	}
	if (o==-1)
	{
		LL Inv=Pow(n,MOD-2);
		for (LL u=0;u<n;u++)	a[u]=a[u]*Inv%MOD;
	}
}
LL tmp[N];
void get_inv (LL *f,LL *g,LL n)
{
	if (n==1)	{g[0]=Pow(f[0],MOD-2);return ;}
	get_inv(f,g,n>>1);
	LL nn=n<<1;
	for (LL u=0;u<n;u++) tmp[u]=f[u];
	for (LL u=n;u<nn;u++) g[u]=tmp[u]=0;
	NTT(g,nn,1);NTT(tmp,nn,1);
	for (LL u=0;u<nn;u++) g[u]=((2-g[u]*tmp[u]%MOD)*g[u]%MOD+MOD)%MOD;
	NTT(g,nn,-1);for (LL u=n;u<nn;u++) g[u]=0;
}
void dao (LL *f,LL *g,LL n)	{for (LL u=1;u<n;u++)	g[u-1]=f[u]*u%MOD;g[n-1]=0;}
void jifen (LL *f,LL *g,LL n)	{for (LL u=1;u<n;u++) g[u]=f[u-1]*Pow(u,MOD-2);g[0]=0;}
void get_ln (LL *f,LL *g,LL n)
{
	dao(f,A,n);get_inv(f,B,n);
	LL nn=n<<1;
	NTT(A,nn,1);NTT(B,nn,1);
	for (LL u=0;u<nn;u++) A[u]=A[u]*B[u]%MOD;
	NTT(A,nn,-1);jifen(A,g,n);
}
void get_EXP (LL *f,LL *g,LL n)
{
	if (n==1)	{g[0]=1;return ;}
	get_EXP(f,g,n>>1);
	LL nn=n<<1;
	for (LL u=0;u<n;u++) D[u]=g[u];
	get_ln(g,E,n);
	for (LL u=0;u<n;u++) C[u]=(f[u]+MOD-E[u])%MOD;C[0]++;
	for (LL u=n;u<nn;u++) C[u]=D[u]=0;
	NTT(C,nn,1);NTT(D,nn,1);
	for (LL u=0;u<nn;u++) C[u]=C[u]*D[u]%MOD;
	NTT(C,nn,-1);
	for (LL u=0;u<n;u++) g[u]=C[u];
}
int main()
{
	scanf("%lld%lld",&n,&m);
	inv[1]=1;for (LL u=2;u<=n;u++) inv[u]=(MOD-MOD/u)*inv[MOD%u]%MOD;
//	printf("%lld\n",5*inv[5]%MOD);
	for (LL u=1;u<=m;u++)
	{
		LL a,b;
		scanf("%lld%lld",&a,&b);
		if (a>n) continue;
		t[a]++;if (b>0&&a*(b+1)<=n) t[a*(b+1)]--;
	}
	for (LL u=1;u<=n;u++)
	{
		if (t[u]<0)t[u]=t[u]+MOD;
		for (LL i=1;i*u<=n;i++)
			F[i*u]=(F[i*u]+t[u]*inv[i]%MOD)%MOD;
	}
	
	/*scanf("%lld",&n);
	for (int u=0;u<n;u++) scanf("%lld",&F[u]);*/
	LL nn=1;while (nn<=n) nn<<=1;
	get_EXP(F,G,nn);
	for (LL u=1;u<=n;u++) printf("%lld\n",G[u]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值