• Codeforces Round #638 (Div. 2) E. Phoenix and Berries dp


    Codeforces Round #638 (Div. 2) E. Phoenix and Berries dp

    题意

    有n个灌木丛,每个灌木丛有(a_i)个红色浆果,(b_i)个蓝色浆果。一个篮子可以装k个浆果,并且每个篮子只能承载要么是同一个灌木丛摘下来的浆果,要么是同一颜色的浆果,问最多装满多少个篮子(n<=500,k<=500)

    分析

    首先数据很DP,往DP靠一靠。最关键的是要发现每个灌木丛最多只能产出一个混色的篮子(因为假如你产生了多个混色篮子,那么他们可以经过互相交换,最后剩下一个混色的篮子),能想到这一步,这一题也就好做了。
    要想知道这个混色篮子有几个红的几个蓝的,只要枚举就行了,那么组成完混色篮子后,同色的能产生多少个呢?我们只需要记录一下状态即可,可以只记录红的或者蓝的,另外一个可以O(1)算出来(DP常用的手段),也就是说用一维扫1--n个篮子,一维记录红的或者蓝的(我们这里选红的)的剩余数量,这里的数量一定是小于k的,因为如果大于k直接组成篮子加进dp值就行了。
    所以我们设置状态为dp[i][j]前i个篮子剩下j个红的时候的最大篮子数量
    我们设前i-1个的红蓝和为sum,此时红色的剩余数量为(j+a[i]),蓝色的剩余数量为(sum-dp[i-1][j]*k-j+b[i])
    所有当能组成混色蓝色时,我们设有红的z个,那么蓝的就有k-z个,转移为
    (dp[i][(j+a[i]-z)\%k]=max(dp[i][(j+a[i]-z)\%k],dp[i-1][j]+1+(j+a[i]-z)/k+(sum-j-k*(dp[i-1][j])-(k-z)+b[i])/k))
    不组成混色篮子的时候转移为
    (dp[i][(j+a[i])\%k]=dp[i-1][j]+(j+a[i])/k+(sum-j-dp[i-1][j]*k+b[i])/k;)
    能和不能状态相同的时候取最大即可
    复杂度(O(nk^2))有点极限,不过1.25e8,2秒也差不多
    ps:刚开始a[i],b[i]用的long long,cf的机器好像是32位的,直接卡掉了,改成了int就过了。。下次碰到这种情况可以考虑一下快读,偷懒fst就凉了

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define F first
    #define S second
    #define mkp make_pair
    #define pii pair<int,int>
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const int maxn=5e3+4;
    ll dp[maxn][maxn];
    int a[maxn],b[maxn];
    int main(){
    	int n,k;
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]);
    	memset(dp,-1,sizeof(dp));
    	dp[0][0]=0;
    	ll sum=0;
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<k;j++){
    			if(dp[i-1][j]==-1)continue;
    			dp[i][(j+a[i])%k]=dp[i-1][j]+(j+a[i])/k+(sum-j-dp[i-1][j]*k+b[i])/k;
    			for(int z=0;z<k;z++){
    				if(a[i]>=z&&b[i]>=(k-z))
    				dp[i][(j+a[i]-z)%k]=max(dp[i][(j+a[i]-z)%k],dp[i-1][j]+1+(j+a[i]-z)/k+(sum-j-k*(dp[i-1][j])-(k-z)+b[i])/k);
    			}
    		}
    		sum+=a[i]+b[i];	
    	}
    	/*for(int i=1;i<=n;i++){
    		for(int j=0;j<k;j++){
    			cout<<dp[i][j]<<" ";
    		}
    		cout<<endl;
    	}*/
    	ll ans=0;
    	for(int i=0;i<k;i++)ans=max(ans,dp[n][i]);
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    _I、_O、_IO的含义
    ARM启动代码中_main 与用户主程序main()的区别
    ARM汇编程序中的伪指令
    oracle密码过期问题
    等待界面-调转页面前button篇
    等待效果
    winfrom中Application.Restart()
    自动刷新处理
    泛微E8二次开发
    我的菜园子
  • 原文地址:https://www.cnblogs.com/ttttttttrx/p/12824875.html
Copyright © 2020-2023  润新知