【好题】dp降维转化+数学+贪心——cf1348E

这题dp的状态设计值得学习,由于多状态复杂度会爆炸,所以考虑降维

如果可以用一个维度求出另一个维度的状态(即两个维度的值可以看做是绑定在一起的),那么就可以降下一维了

这题还有点卡常。。评测机快就能跑过去。。

/*
很容易想到用dp[i][j][k]来表示前i棵树,留下j个红果子,k个蓝果子状态下可以装满的最大篮子数
但是复杂度为nk^4,所以想办法优化掉一维

可以推出一个结论:每棵树最多只有一篮子是混色的 
其实只需要考虑红果子的余数即可,dp[i][j]表示前i棵树,红果子余下j个的最大篮子数,
    此时前i棵树蓝果子的余数是可以算出来的 sum[i]-dp[i][j]*K-j 
那么枚举第i+1棵树混色篮子的红果子树x,对应蓝果子数K-x
余下所有红果子数 last1=j+a[i+1]-x
余下所有蓝果子数 last2=(sum[i]-dp[i][j]*k-j)+(b[i+1]-(k-x))
要更新的状态就是dp[i+1][last1%K]    
*/
#include<bits/stdc++.h>
using namespace std;
#define N 505
#define ll long long 

ll n,k,a[N],b[N],sum[N],dp[N][N];

int main(){
    cin>>n>>k;
    for(register  int i=1;i<=n;i++)scanf("%lld%lld",&a[i],&b[i]);
    for(register  int i=1;i<=n;i++)
        sum[i]=sum[i-1]+a[i]+b[i];
    memset(dp,-1,sizeof dp);
    dp[0][0]=0;
    
    for(register int i=0;i<n;++i){
        for(register  int j=0;j<k;++j)if(dp[i][j]>=0){
            //没有混色篮子
            ll last1=j+a[i+1];
            ll last2=(sum[i]-dp[i][j]*k-j)+b[i+1]; 
            dp[i+1][last1%k]=max(dp[i+1][last1%k],dp[i][j]+last1/k+last2/k);
            
            for(register  int x=1;x<k;++x)if(x<=a[i+1] && (k-x)<=b[i+1]){
                ll last1=j+a[i+1]-x;
                ll last2=(sum[i]-dp[i][j]*k-j)+(b[i+1]-(k-x));
                dp[i+1][last1%k]=max(dp[i+1][last1%k],dp[i][j]+1+last1/k+last2/k);
            }
        }
    }
    
    ll mx=0;
    for(register  int j=0;j<k;++j)
        mx=max(mx,dp[n][j]);
    cout<<mx<<'
';
}
  
原文地址:https://www.cnblogs.com/zsben991126/p/12893261.html