Codeforces 999F Cards and Joy 【dp】【性质】
?讀完這道題后應該想到牌有多少張都是什么不重要,重要的是player的favorite number是怎么分配的。(因為不是任何player的favorite number不能帶來任何joy)然后每個favorite number帶來的joy互相不受影響,因為如果favorite number不一樣,對應的player肯定不一樣。因此我們可以計算每個【favorite number帶來的貢獻】。
因此想到dp[i][j]代表i個人分j個favorite number的最大joy(favorite number具體是多少其實不重要),
轉移方程 dp[i][j] = dp[i-1][j-c] + h[c] ? 枚舉第i個人拿c張牌// c = 0 - min(j,k) 【因為一個人最多拿k張牌】,代價為k
所以整體復雜度是n* (n*k) * k ==> O(n^2 * k^2)。能過
然后這道題我用遞歸和遞推都寫了一遍,兩個速度差不多。遞推并不能保證比遞歸快,關鍵還是看狀態數
?
再補充一下轉移代價與時間復雜度之間為什么是相乘的關系,我以前一直沒想清楚:
實際上是這一層的狀態得到要考慮上一層的j個狀態,然后這一層的每個狀態都要考慮到上一層的j個狀態,上一層的狀態被重復考慮了。這就是為什么【簡單運用】的話線段樹能優化dp,因為能區間max,但實際上很復雜,聽說要涉及凸包orz
?
1 #include<iostream> 2 #include<map> 3 #include<cstring> 4 using namespace std; 5 6 7 //只需要考慮每個number帶來的貢獻,不是任何人favorite number的數沒有貢獻 8 int a[5005],h[15],favorite[505];//favorite[i]為第i個player的favorite number 9 int vis[100005],ans; 10 map<int,int> m1,m2; 11 12 int dp[505][5005];// dp[i][j]為i個人分j個favorite number的最大joy 13 14 int main(){ 15 int n,k; cin>>n>>k; 16 for(int i=1;i<=n*k;i++) { 17 cin>>a[i]; 18 m1[ a[i] ] ++;//這個number一共有多少個 19 } 20 for(int i=1;i<=n;i++){ 21 cin>>favorite[i]; 22 m2[ favorite[i] ]++;//這個number是多少人的favorite 23 } 24 for(int i=1;i<=k;i++) cin>>h[i]; 25 26 for(int i=1;i<=n;i++){ 27 for(int j=0;j<=i*k;j++){ 28 for(int c=0;c<=min(j,k);c++) dp[i][j] = max( dp[i][j],dp[i-1][j-c]+h[c] );//第i個人分c個favorite number 29 } 30 } 31 32 for(int i=1;i<=n;i++){ 33 if( vis[ favorite[i] ] ) continue; 34 ans+=dp[ m2[favorite[i]] ][ min( m2[favorite[i]]*k, m1[ favorite[i]] ) ]; 35 vis[ favorite[i] ] = 1; 36 } 37 38 cout<<ans; 39 40 return 0; 41 }?
轉載于:https://www.cnblogs.com/ZhenghangHu/p/9226458.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的Codeforces 999F Cards and Joy 【dp】【性质】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么连接新的路由器 如何把新的路由器接入
- 下一篇: 软路由搭建与内网穿透实现方法详解 如何在