1. 程式人生 > >CF1105C Ayoub and Lost Array ——動態規劃

CF1105C Ayoub and Lost Array ——動態規劃

答案 方便 code force color out ref pro 為什麽

CF1105C Ayoub and Lost Array

題意:
一個整數數組,滿足:
1. 長度為n
2. 所有元素都在[l, r]範圍內
3. 所有元素的和能被3整除
給出n, l, r (1 ≤ n ≤ 2*10^5,1 ≤ l ≤ r ≤ 10^9)
請找出符合條件的數組的個數,答案對 10^9 + 7取模


首先我們要處理出[l, r]中對3取模得結果分別為0,1,2的數的個數,在一個合乎要求的數組中,結果為1和2的數的個數必然一樣,由此就可以很方便地得到所有可能的組合的個數。但新的問題來了,由於可以選用相同的數,求出這些組合的排列數幾乎是一個不可能完成的任務(對我這種蒟蒻來說)。

換一種思路,我們一個數一個數地添,並把所有可能的情況都考慮進去:
設dp[i][j]表示有i個數,且它們的和對3取模結果為j的數組個數,數組num[i]中記錄了[l, r]中對3取模得結果為i的數的個數
顯然dp[1][j] = num[j],隨後,向已有的數組的尾部添加新的數字,例如:
dp[i][0] = dp[i - 1][0] * num[0] + dp[i - 1][1] * num[2] + dp[i - 1][2] * num[1]
dp[i][1]和dp[i][2]的情況同理,遞推到n,dp[n][0]就是我們要的答案。

為什麽是添加到尾部?不能插入到某個數字前嗎?這樣做會不會漏情況?
實際上,插入到某個數字之前會帶來重復(會有另一個數被頂到尾部),舉個例子:現在前i - 1個數的和對3取模結果為1,要添加一個結果為2的數,即dp[i - 1][1] * num[2],如果把它插入到前面,使一個對3取模結果為1的數被頂到了前面的話,顯然就與dp[i - 1][2] * num[1]的情況重復了,另外兩種情況同理。


附關鍵部分代碼,歡迎糾錯。

const int mod = 1e9 + 7;
const int maxn = 2e5 + 5;
ll dp[maxn][3];//有i個數,且它們的和對3取模結果為j的數組個數
int main()
{
    //num[i]記錄了對3取模結果為i的數的個數
    dp[1][0] = num[0], dp[1][1] = num[1], dp[1][2] = num[2];
    for(int i = 2; i <= n; i++)
    {
        dp[i][0] = (dp[i - 1][0] * num[0]) % mod + (dp[i - 1
][1] * num[2]) % mod + (dp[i - 1][2] * num[1]) % mod; dp[i][0] %= mod; dp[i][1] = (dp[i - 1][0] * num[1]) % mod + (dp[i - 1][1] * num[0]) % mod + (dp[i - 1][2] * num[2]) % mod; dp[i][1] %= mod; dp[i][2] = (dp[i - 1][0] * num[2]) % mod + (dp[i - 1][1] * num[1]) % mod + (dp[i - 1][2] * num[0]) % mod; dp[i][2] %= mod; } cout << dp[n][0] << endl; }

CF1105C Ayoub and Lost Array ——動態規劃