• JZOJ 6309. 完全背包(矩阵max)


    JZOJ 6309. 完全背包

    题目

    Description

    在这里插入图片描述

    Input

    在这里插入图片描述

    Output

    在这里插入图片描述

    Sample Input

    Sample 1:
    2 15
    3 2
    5 3

    Sample 2:
    3 70
    71 100
    69 1
    1 2

    Sample Output

    Sample 1:
    10

    Sample 2:
    140

    Data Constraint

    在这里插入图片描述

    题解

    • 乍一看,这不就是非常裸的完全背包吗???
    • 再看看范围,背包容量极大,但是,物品的代价却很小。
    • 如果直接打最裸的完全背包,时间复杂度是 O ( n m ) O(nm) O(nm),能得到 20 20 20分;
    • 如果对于代价相同的,只用收益最大的一个转移,时间复杂度是 O ( M a x a i m ) O(Max_{a_i}m) O(Maxaim,能得到 60 60 60分;
    • 看到这么大的 m m m,不难想到矩阵
    • 设初始一维矩阵 v [ i ] ( i ∈ [ 0 , 100 ] ) v[i](iin [0,100]) v[i](i[0,100])表示花费 i i i的代价最大能有多少收益(可以选多个,如同容量为 i i i的完全背包),
    • 不难发现,有了这个就可以用两个 i ∈ [ 0 − 100 ] iin[0-100] i[0100]得到 i ∈ [ 100 , 200 ] iin[100,200] i[100,200],用两个 i ∈ [ 100 , 200 ] iin [100,200] i[100,200]得到 i ∈ [ 300 , 400 ] iin [300,400] i[300,400]……以此类推。
    • 那么自然想到矩阵快速幂,因为每次可以得出 100 100 100个的答案,所以快速幂的指数设为 ⌊ m 100 ⌋ + 1 lfloorfrac{m}{100} floor+1 100m+1
    • 每次先用当前的矩阵 f f f与自己相加取 m a x max max,然后用 v v v更新一遍 f f f
    • 如果指数为奇数,再用 f f f v v v相加得到新的 f f f
    • 最后的答案即为 f [ m m o d    100 ] f[mmod 100] f[mmod100]

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    ll v[110],f[110],c[110];
    void ksm(ll x)
    {
    	int i,j;
    	if(x==1) 
    	{
    		for(i=0;i<=100;i++) f[i]=v[i];
    		return;
    	}
    	ksm(x/2);
    	memset(c,0,sizeof(c));
    	for(i=0;i<=100;i++)
    		for(j=0;j<=100;j++)
    			if(i+100-j>=0&&i+100-j<=100) c[i]=max(c[i],f[j]+f[i+100-j]);
    	for(i=0;i<=100;i++)
    		for(j=0;j<=i;j++) c[i]=max(c[i],c[j]+v[i-j]);
    	for(i=0;i<=100;i++) f[i]=c[i];
    	if(x%2)
    	{
    		memset(c,0,sizeof(c));
    		for(i=0;i<=100;i++)
    			for(j=0;j<=100;j++)
    				if(i+100-j>=0&&i+100-j<=100) c[i]=max(c[i],f[j]+v[i+100-j]);
    		for(i=0;i<=100;i++)
    			for(j=0;j<=i;j++) c[i]=max(c[i],c[j]+v[i-j]);
    		for(i=0;i<=100;i++) f[i]=c[i];
    	}
    }
    int main()
    {
    	int n,i,j,x,y;ll m;
    	scanf("%d%lld",&n,&m);
    	for(i=1;i<=n;i++)
    	{
    		scanf("%d%d",&x,&y);
    		if(y>v[x]) v[x]=y;
    	}
    	for(i=1;i<=100;i++) 
    		for(j=1;j<i;j++) v[i]=max(v[i],v[j]+v[i-j]);
    	ksm(m/100+1);
    	printf("%lld",f[m%100]);
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    Restful API
    事件冒泡
    DOM性能
    获取dom节点的所有子节点
    获取dom节点的父节点
    深拷贝
    Dropdown下拉菜单
    Breadcrumb面包屑
    【vue】----生产环境去除cosole.*
    刷leetcode时,重新认识LinkedList实现栈、队列或者双端队列
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910065.html
Copyright © 2020-2023  润新知