【好题】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<<'\n'; }