計數DP,牛客練習賽41B題 666RPG

2021-09-11 18:13:22 字數 1391 閱讀 7003

傳送門

lililalala正在玩一種有 n個回合的回合制rpg遊戲,初始分數為0,第 i i個回合lililalala有如下兩種選擇。

a.將分數加上 ai ai

b.將分數 ×-1 ×-1

lililalala同樣也很討厭野獸數 666 ,但是他很卻喜歡數字 -666 -。他想知道有多少種不同的方案使得n個回合後分數變為 -666且在任何乙個回合之後分數都不為 666。

如果兩種方案有任何乙個回合選擇不同,就認為這兩種方案是不同的。

答案請對 10^8+7 取模。

輸入描述:

輸入包含兩行。

第一行乙個整數 n(1≤n≤300) n(1≤n≤300)。

第二行 n n個整數 a1a2a3…an(-666≤ a1a2a3…an≤666) a1a2a3…an(-666≤ a1a2a3…an≤666)。

輸出描述:

輸出一行乙個整數–符合條件的不同方案數。輸入3

-333 -333 -333輸出1

說明僅一種符合條件的方案

第一回合選擇將分數×−1。分數為0

第二回合選擇將分數加上-333。分數為 -333

第三回合選擇將分數加上 -333。分數為 -666輸入3

333 333 333輸出0

輸入13

518 -643 -503 424 -76 -18 547 26 51 -647 -457 -5 329輸出2

計數dp.

dp[i][j]代表第i個回合後分數為j的方案數

則:dp[i][j]=dp[i-1][j-ai]+dp[i-1][-j]

因為開二維記憶體不夠,需要使用滾動陣列, 同時, 避免負數的影響用dp[i][j+add] 來代表第i個回合後分數為j的方案數。因為j最小為300 * -666 這裡取add = 300 * 666。

特判遮蔽所有來自j=666的狀態轉移

計數dp不太熟悉, 卡了很久在 dp[cnt][j+add]=dp[cnt^1] [j-a[i]+add]+dp[cnt^1][-j+add];

之前是分開寫的用了+= 但這裡用到了滾動陣列, 前面一輪算的數會保留到這一輪, 用+= 會造成錯誤。

#include#include#include#includeusing namespace std;

const int add = 300*666, mod = 1e8 + 7;

int a[310];

int dp[2][add * 2]; //j的範圍由300 * -666 到 300 * 666 改為 0 ~ 300 * 666 * 2

int main()}}

printf("%d", dp[n % 2][add - 666]);

}

牛客練習賽41 B 666RPG(計數dp)

思路 我們可以用 則可以得狀態轉移方程為 但是 include using namespace std define ll long long const int n 1e6 7 const int base 301 666 const int mod 1e8 7 int a 305 ll dp 2...

演算法小講堂 動態規劃!之牛客練習賽41 B題

說來實在慚愧,已經很久沒有更新部落格了。反正也沒人看 偷笑 那麼今天就更新一道dp型別的題目。所謂 dp 好,好到頭髮少。另外需要補充的一點是呢,這題我在時限內並沒有寫出來,可謂菜的開花 直接開花 但是我覺得這個dp的手法十分有用,所以我就很厚臉皮更上了一期,當然也會盡量把思路說的的比較詳細啦。看題...

牛客練習賽41

相當於求n個點,已知n條邊,組成各個連通分塊,每個連通分塊有乙個和值,求出最大的幾個和值。用並查集給邊建立聯絡,計算連通塊和是 先找到那個fa點 再給該點加值。include include include include include includeusing namespace std typ...