Codeforces 1398D - Colored Rectangles (dp)
阿新 • • 發佈:2020-08-15
題意
給定三個集合\(\{R\},\{G\},\{B\}\)
要求任選兩個集合並分別取出一個數字,相乘後加入答案
問答案最大可能是多少
限制
Time limit per test: 2 seconds
Memory limit per test: 256 megabytes
\(1\leq R,G,B\leq 200\)
\(1\leq r_i,g_i,b_i\leq 2000\)
解
考慮動態規劃
貪心可得,每次取出的兩個數一定是對應集合內最大的數字
所以先按照數值從大到小排序
令\(dp[i][j][k]\)表示\(\{R\}\)集合中取了(前)\(i\)
那麼我們考慮轉移到當前狀態的情況
如果當前狀態是由取出\(\{R\},\{G\}\)兩個集合的元素得到的,那麼\(dp[i][j][k]=dp[i-1][j-1][k]+a[i]*b[j]\)
如果當前狀態是由取出\(\{R\},\{B\}\)兩個集合的元素得到的,那麼\(dp[i][j][k]=dp[i-1][j][k-1]+a[i]*c[k]\)
如果當前狀態是由取出\(\{G\},\{B\}\)兩個集合的元素得到的,那麼\(dp[i][j][k]=dp[i][j-1][k-1]+b[j]*c[k]\)
由於答案要取最值,先忽略邊界情況,則得到的狀態轉移方程為
\[dp[i][j][k]=max \left \{ \begin{aligned} dp[i-1][j-1][k]+a[i]*b[j]\\ dp[i-1][j][k-1]+a[i]*c[k]\\ dp[i][j-1][k-1]+b[j]*c[k] \end{aligned} \right \} \]
最後處理下邊界情況即可
注意每次轉移就嘗試更新答案
完整程式
(啊還沒終測呢……)
#include<bits/stdc++.h> using namespace std; typedef long long ll; int a[222],b[222],c[222]; ll dp[222][222][222]; void solve() { int R,G,B; cin>>R>>G>>B; for(int i=1;i<=R;i++) cin>>a[i]; for(int i=1;i<=G;i++) cin>>b[i]; for(int i=1;i<=B;i++) cin>>c[i]; sort(a+1,a+1+R,greater<int>()); sort(b+1,b+1+G,greater<int>()); sort(c+1,c+1+B,greater<int>()); memset(dp,-0x3f,sizeof dp); dp[0][0][0]=0; ll ans=0; for(int i=0;i<=R;i++) //注意從0開始列舉 for(int j=0;j<=G;j++) for(int k=0;k<=B;k++) { if(i&&j&&k) //四種可轉移的情況 dp[i][j][k]=max(dp[i-1][j-1][k]+a[i]*b[j],max(dp[i-1][j][k-1]+a[i]*c[k],dp[i][j-1][k-1]+b[j]*c[k])); else if(i&&j) dp[i][j][k]=dp[i-1][j-1][k]+a[i]*b[j]; else if(i&&k) dp[i][j][k]=dp[i-1][j][k-1]+a[i]*c[k]; else if(j&&k) dp[i][j][k]=dp[i][j-1][k-1]+b[j]*c[k]; ans=max(ans,dp[i][j][k]); } cout<<ans<<'\n'; } int main() { ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); solve(); return 0; }