zoukankan      html  css  js  c++  java
  • LOJ #6268. 分拆数

        可以先将问题建模为 : 物品大小为1~inf 且每件物品数量无限 的背包选体积为1~n的方案数。

        显然物品体积只有1~n有用,我们不妨把 体积1~sqrt(n) 的物品先暴力插入到背包中,设这一部分最后 体积i的方案数是 A[i] 。

        考虑体积>sqrt(n)的物品怎么计算方案,可以发现这样的物品最多只能有sqrt(n)件。

        这有什么用呢? 当然是dp用啊! 设f[i][j] 为选了i件>sqrt(n)的物品,且总体积是j的方案数,显然第一维只有sqrt(n),直接转移做就行了,设这一部分最后 体积i的方案数是B[i]。

        不过还有一点很恶心:我们还要合并 A[] 与 B[]。

        也没啥,写个NTT就好了hhhh

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=100005,root=3,ha=998244353,inv=ha/3+1,Base=333;
    inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;}
    inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;}
    void W(int x){ if(x>=10) W(x/10); putchar(x%10+'0');}
    int A[maxn*4],F[Base+5][maxn],B[maxn*4],r[maxn*4],n,l,S,N,INV;
    inline int ksm(int x,int y){ int an=1; for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha; return an;}
    
    inline void dp(){
    	A[0]=1;
    	for(int i=1;i<Base;i++)
    	    for(int j=i;j<=n;j++) ADD(A[j],A[j-i]);
    	    
    	F[0][0]=1,S=maxn/Base+1,F[1][Base]=1;
    	for(int i=1;i<S;i++)
    	    for(int j=0;j<=n;j++) if(F[i][j]){
    	    	if(j+i<=n) ADD(F[i][j+i],F[i][j]);
    	    	if(j+Base<=n) ADD(F[i+1][j+Base],F[i][j]);
    	    	ADD(B[j],F[i][j]);
    		}
    	ADD(B[0],1);
    }
    
    inline void NTT(int *c,int f){
    	for(int i=0;i<N;i++) if(i<r[i]) swap(c[i],c[r[i]]);
    	
    	for(int i=1;i<N;i<<=1){
    		int omega=ksm((f==1?root:inv),(ha-1)/(i<<1));
    		for(int P=i<<1,j=0;j<N;j+=P){
    			int now=1;
    			for(int k=0;k<i;k++,now=now*(ll)omega%ha){
    				int x=c[j+k],y=c[j+k+i]*(ll)now%ha;
    				c[j+k]=add(x,y);
    				c[j+k+i]=add(x,ha-y);
    			}
    		}
    	}
    	
    	if(f==-1) for(int i=0;i<N;i++) c[i]=c[i]*(ll)INV%ha;
    }
    
    int main(){
    	scanf("%d",&n),dp();
    	
    	for(N=1;N<=(n<<1);N<<=1) l++;
    	for(int i=0;i<N;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    	NTT(A,1),NTT(B,1);
    	for(int i=0;i<N;i++) A[i]=A[i]*(ll)B[i]%ha;
    	INV=ksm(N,ha-2),NTT(A,-1);
    	
    	for(int i=1;i<=n;i++) W(A[i]),puts("");
    	return 0;
    }
    

      

  • 相关阅读:
    python 软件目录结构规范 与 模块导入
    Python 序列化之json&pickle模块
    损失函数总结
    从1到n整数中1出现的次数(Java)
    随手编程---快速排序(QuickSort)-Java实现
    从上往下打印二叉树(剑指offer_32.1)
    栈的压入、弹出序列(剑指offer_31)
    63. 搜索旋转排序数组 II(回顾)
    643. 最长绝对文件路径(回顾)
    40. 用栈实现队列
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8954965.html
Copyright © 2011-2022 走看看