NOIP2007 矩陣取數遊戲(區間DP)

2022-05-05 18:42:08 字數 1862 閱讀 7782

傳送門

這道題第一眼看上去可能讓人以為是貪心……不過貪心並不行,因為每次的操作是有2的冪次方的權值的。這樣的話直接每次貪心最小的就目光短淺。所以那我們自然想到了dp。

據說這是一道很正常的區間dp?

區間dp的基本思想,就是先處理出小區間的最優解,再由多個小區間合併成乙個大區間。

不過這道題的想法略微有些不同。首先從題目描述上來看,每行的取數是獨立的,對於每一行我們來分析一下。

首先,因為題目中說只能取一行元素當前的首個元素或者末尾元素。既然如此,我們假設dp[i][j]表示選取區間i~j所能獲得的最大值。

這樣的話,dp[i][j]就只能從兩方面轉移過來。一是dp[i+1][j],二是dp[i][j-1].這樣的話,我們考慮一下轉移時候的狀態。因為每次轉移所獲的的分數是當前選取的數值乘以2^選舉的次數,所以我們可以這麼想,對於乙個內部的區間,它在被轉移的時候,本身是要被*2的。之後這種狀態就會被繼續跟隨著*2,所以選到最後必然是符合題意的。

所以說dp的方程就是dp[i][j] = min(dp[i+1][j]*2 + a[i] * 2,dp[i][j-1]*2 + a[j]*2);

dp方程說完了,之後說該怎麼dp。我們知道區間dp的思想是先算小區間,之後合併成大區間,所以我們可以從0~n-1列舉區間長度,之後列舉區間的左右端點進行轉移。

還有就是這道題要使用高精度……不過可以選擇自己寫乙個高精乘,高精加,和高精度比較的struct,直接封裝起來。這樣就可以了。

看一下**(因為高精模板是抄的……高精減可以忽略……)

#include#include

#include

#include

#define rep(i,a,n) for(ll i = a;i <= n;i++)

#define per(i,n,a) for(ll i = n;i >= a;i--)

#define enter putchar('\n')

using

namespace

std;

const

int m = 105

;typedef

long

long

ll;int

read()

while(ch >= '

0' && ch <= '9'

)

return ans *op;

}struct

big big(

intp)

void init(int

p)

big

operator + (const big &g) const

if(ans.num[s+1]) ans.len++;

return

ans;

}big

operator - (const big &g) const

big

operator * (const big &g) const

if(!ans.num[k]) k--;

ans.len =k;

return

ans;

}friend big bmax(

const big &f,const big &g)

}return

f; }

void

out()

};big a,b,c,f[

81][81],dp[81][81][81],ans,pow2[81

],now;

intn,m;

intmain()

ans = ans + dp[i][1

][m];

}ans.

out();

return0;

}

NOIP2007 矩陣取數遊戲

傳送門給定乙個n m的矩陣,在每一行中取m次數,每次取數只能從行首或尾取數,第i次取數的貢獻是 2 i 該點值 操作n行,求最大答案 n,m 80 不難發現行與行之間是完全獨立的,所以單獨處理每一行就好了 考慮區間dp 設 dp i j 表示區間i j的答案最大值 則有 dp i j max num...

NOIP2007 矩陣取數遊戲

鏈結 簡單dp 毒瘤高精 顯然行與行沒有關聯 所以只需要每行處理 考慮dp i,j,k 表示第i次取數,第j行,有k次取的頭的最大分數 直接dp即可 includeusing namespace std define ll int128inline intread while ch 0 ch 9 d...

noip2007矩陣取數遊戲 2008 11 5

noip2007矩陣取數遊戲 2008.11.5 注意 比大小位數不相同時,取位數大的數大 當位數相同時,要從最高位開始比較,相同,則往下比,不相同,則大的數就大。我剛開始,弄成了從最低位開始比較,故,wa了 20多分鐘 小結 這道題,我打了不下 5遍,一定要先想好,在紙上把每個細節都確定了,並確定...