zoukankan      html  css  js  c++  java
  • LOJ #6089. 小 Y 的背包计数问题

    LOJ #6089. 小 Y 的背包计数问题


    神仙题啊orz。

    首先把数分成(<=sqrt n)的和(>sqrt n)的两部分。

    (>sqrt n)的部分因为最多选(sqrt n)个数,所以数量就没有卵用了。然后就用完全背包的一个常见套路(?)可以对一个空的序列整体+1或者在最左边加上一个(sqrt n+1),这个操作序列和完全背包的选择方案一一对应。感性理解一下是对的emmmm,复杂度(O(nsqrt n))

    (<=sqrt n)的部分只有(sqrt n)个数,就可以多重背包做,然后用剩余系优化。
    剩余系就是说多重背包方案的转移方程是(f[i][j]=sum_{k=1}^{i}f[i-1][j-ki])这个样子的

    可以发现转移过来的j都和原来的j同余(( ext{mod } i))

    对于每一个( ext{mod }i)的余数做一个f的前缀和,转移过来的一定是连续的一段

    orz

    #include<bits/stdc++.h>
    #define il inline
    #define vd void
    typedef long long ll;
    il int gi(){
    	int x=0,f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){
    		if(ch=='-')f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    #define mod 23333333
    ll f[320][100010];
    ll h[100010],s[100010];
    int main(){
    	int n=gi(),m=int(sqrt(n));
    	f[0][0]=1;s[0]=1;
    	for(int i=1;i<=m;++i)
    		for(int j=0;j<=n;++j){
    			if(j>i)f[i][j]+=f[i][j-i];
    			if(j>m)f[i][j]+=f[i-1][j-m-1];
    			f[i][j]%=mod;
    			s[j]=(s[j]+f[i][j])%mod;
    		}
    	memset(f,0,sizeof f);f[0][0]=1;
    	for(int i=1;i<=m;++i){
    		for(int j=0;j<i;++j){
    			int t=0;
    			for(int k=j;k<=n;k+=i)h[++t]=f[i-1][k];
    			for(int k=2;k<=t;++k)h[k]=(h[k]+h[k-1])%mod;
    			for(int k=j,tot=0;k<=n;k+=i){
    				++tot;
    				f[i][k]=(f[i][k]+h[tot]-h[std::max(0,tot-i-1)]+mod)%mod;
    			}
    		}
    	}
    	ll ans=0;
    	for(int i=0;i<=n;++i)ans+=s[i]*f[m][n-i]%mod;
    	printf("%lld
    ",ans%mod);
    	return 0;
    }
    
  • 相关阅读:
    复合文字(C99)
    复浮点数(C99)
    字符串的数组形式与指针形式
    《设计模式之禅》学习笔记(十)
    旧关键字的新位置(C99)
    C的存储类、链接和内存管理
    scanf( )函数的格式化输入
    《设计模式之禅》学习笔记(十三)
    yum软件包管理器
    《设计模式之禅》学习笔记(十五)
  • 原文地址:https://www.cnblogs.com/xzz_233/p/9674940.html
Copyright © 2011-2022 走看看