zoukankan      html  css  js  c++  java
  • [提高组集训2021] 妹妹卡组

    一、题目

    妹妹 ( t Oneindark) 给了你 (n) 个卡组,对于每个卡组有 (k_i) 个卡牌,其中第 (j) 个卡牌的大小是 (j),价值是 (a_{i,j}),每个卡组只能选取一张卡牌。

    如果卡牌栏的大小为 (t),那么能获得的最大价值是多少,你需要对 (tin[n,sum k_i]) 都分别求一次,因为 ( t Oneindark) 会向你撒娇,所以你需要快速把它们都求出来~~

    (nleq 10^5,kleq 5)

    二、解法

    (f(i,j)) 为考虑前 (i) 个卡组大小为 (j) 的最大价值,首先有一个根本想不到的结论:把 (j) 这一维模 (12) 意义下分组后,每一组的 (dp) 值关于 (j) 有凸性,设 (D=12),证明:

    首先给出引理:对于若干个和为 (24) 且在 (in{0,1,2,3,4}) 中的元素,可以划分成和为 (12) 的两组。

    我们首先把卡牌的大小都减去 (1)(方便套用引理),然后考虑 (f(x-D)) 调整到 (f(x+D)) 的过程,设第 (i) 组卡牌的变化量是 (d_i),有 (sum d_i=24),且 (d_iin[-4,4])

    那么我们可以把若干个 (d_i) 组合起来,使得和在 (in[0,4]) 中,然后我们把 (d_i) 划分成两组,代价变化多的一组就应用到 (f(x-D))(f(x)) 这个过程上,所以有:

    [f(x)-f(x-D)geq f(x+D)-f(x) ]

    知道此结论我们把第一维分治,问题变成了合并两个 (dp) 数组,那么我们花费 (O(D^2)) 枚举两个组,因为每组内部有相同的凸性,所以可以双指针合并(选增量大的那个),时间复杂度 (O(frac{len}{D})),所以总时间复杂度 (O(Dcdot (nk)log nk))

    三、总结

    对于可以快速合并的背包,可以用分治的方法优化。

    但是这个凸性真的不太明白啊

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    #define int long long
    const int M = 200005;
    const int D = 12;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k[M],sum,dp[5*M],a[M][5];
    void div(int l,int r,int *dp)
    {
    	if(l==r)
    	{
    		for(int i=0;i<k[l];i++)
    			dp[i]=a[l][i];
    		return ;
    	}
    	int mid=(l+r)>>1,ll=(mid-l+1)*5,lr=(r-mid)*5;
    	int f[ll+5],g[lr+5];
    	memset(f,-0x3f,sizeof f);
    	memset(g,-0x3f,sizeof g);
    	div(l,mid,f);div(mid+1,r,g);
    	for(int x=0;x<D;x++) for(int y=0;y<D;y++)
    	{
    		if(x>=ll || y>=lr) continue;
    		dp[x+y]=max(dp[x+y],f[x]+g[y]);
    		int i=x,j=y;
    		while(i+D<ll || j+D<lr)
    		{
    			int f1=i+D<ll,f2=j+D<lr;
    			if(!f1 || (f2 && g[j+D]-g[j]>f[i+D]-f[i]))
    			{
    				dp[i+j+D]=max(dp[i+j+D],f[i]+g[j+D]);
    				j+=D;
    			}
    			else
    			{
    				dp[i+j+D]=max(dp[i+j+D],f[i+D]+g[j]);
    				i+=D;
    			}
    		}
    	}
    }
    signed main()
    {
    	freopen("fake.in","r",stdin);
    	freopen("fake.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++)
    	{
    		sum+=k[i]=read();
    		for(int j=0;j<k[i];j++)
    			a[i][j]=read();
    	}
    	memset(dp,-0x3f,sizeof dp);
    	div(1,n,dp);
    	for(int i=0;i<=sum-n;i++)
    		printf("%lld ",dp[i]);
    	puts("");
    }
    
  • 相关阅读:
    轻量级数据库sqlite的使用
    Integer引发的思考
    css限制显示行数
    数据库 chapter 17 数据仓库与联机分析处理技术
    数据库 chapter 15 对象关系数据库系统
    数据库 chapter 16 XML数据库
    数据库 chapter 14 分布式数据库系统
    数据库 chapter 11 并发控制
    数据库 chapter 12 数据库管理系统
    数据库 chapter 13 数据库技术新发展
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15367355.html
Copyright © 2011-2022 走看看