普普通通的DP(按位貪心DP)

2021-10-07 05:19:33 字數 1904 閱讀 6525

題意:還記得這題嗎?cf1332d 就是說乙個二維矩陣,從(1,1)走到(n,m),只能向下或右走,獲得的總貢獻是每一步的&運算,問你最後能獲得多少貢獻。

思路:我們很容易想到,dp[i][j]表示走到(i,j)的最大值,然後每步取大就行,但是這個方法是錯誤的,比如這個資料:

3 4

7 3 3 1

4 8 3 6

7 7 7 3

按照這種dp,答案是2,但是其實我們可以得到的最大貢獻為3。因為我們要的是按位&的結果最大,但是可能到倒數第二步是有兩種,一種是1000,還有一種是0100,但是a[n][m]是0110,按照原來dp的思路,倒數第二步存了1000,和最後一步按位與之後,答案變成了0,但是如果倒數第二步是0100,這樣結果就是0100。

所以我們要獲得最大價值,那麼首先應該考慮的是高位,因為2i >(2i-1 + 2i-2 +…+20 ) 所以這個貪心方案是正確的。

我們從高位到低位遍歷,之後再取低位的時候要首先滿足這條路符合之前的選擇。

我們用dp[i][j]表示在取第b位的時候能否走到(i,j),如果能,就從這個點出發,看是否能走下一步,最後如果這一位能走到(n,m),就把最後的總貢獻加上(1<#include

#define endl '\n'

#define null null

#define ls p<<1

#define rs p<<1|1

#define fi first

#define se second

#define mp make_pair

#define pb push_back

#define ll long long

#define int long long

#define pii pair

#define ull unsigned long long

#define all(x) x.begin(),x.end()

#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

#define ct cerr<<"time elapsed:"<<1.0*clock()/clocks_per_sec<<"s.\n";

char

*fs,

*ft,buf[

1<<20]

;#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;

inline

intread()

while

(ch>=

'0'&&ch<=

'9')

return x*f;

}using

namespace std;

const

int n=

1e3+5;

const

int inf=

0x3f3f3f3f

;const

int mod=

1e9+7;

const

double eps=

1e-7

;const

double pi=

acos(-

1);int a[n]

[n],dp[n]

[n];

signed

main()

int ans=0;

for(

int b=

31;b>=

0;b--)}

}if(dp[n]

[m]&&

(a[n]

[m]&(1

1<} cout<}

SCPC 普普通通的DP(字面意思)

給你乙個n m的矩陣,你需要從左上角走到右下角,你每次只能向下或者向右走,並且不能走出矩陣之外。只要你走到終點之後,你就會獲得獎勵,獎勵的金額為 所有經過的元素做 與 運算。算一算你能獲得的最大獎勵金額為多少。位置越高對答案影響越大,所以我們從高位到低位開始跑,計算每一位是否能有數字跑到最後且不影響...

數字DP 按位DP

之前說過要做個專題,雖然隔了好長時間。但說話還是算數的,把之前做的ppt翻出來貼上,好吧,我就是懶。見識的還是少,歡迎討論啊 數字dp 在給定區間 a,b 內,找滿足要求的數。要求一般和數大小無關,而與數的組成有關 例如,遞增的,1234,2579 雙峰的,19280,26193 含49的,49,1...

專題 數字DP 按位DP

自 數字dp 在給定區間 a,b 內,找滿足要求的數。要求一般和數大小無關,而與數的組成有關 例如,遞增的,1234,2579 雙峰的,19280,26193 含49的,49,149,1492 整除13的,26,39 麻煩在於,規模大,位數 100 不能列舉。區間往往不是整百整千,邊界問題 注意 記...