Our happy ending

來源:互聯網
上載者:User

標籤:位置   acm   數字   name   span   問題:   show   back   沒有   

題目連結

  • 題意:
    輸入n、k、L,n個數,最大值不超過L,在序列中取若干個數和能達到k的序列個數
    n,k<=20 , 0<=L<=10^9
  • 分析:
    題目關鍵在於和k比較小,所以能夠考慮DP。
    先說一下自己比賽時候想到的DP狀態。好久才發現錯了。

    。。。

    DP[i][j]表示當前是序列中的第i個數(必須選),和能取到j的序列個數。

    這個狀態的問題就是在於反覆:對於一個確定的序列來說,由於能夠選取某些數字來求和,所以對於DP[i]來說,同一個序列能夠得到非常多不同的和j,也就是被計算了非常多次從而導致反覆。
    對照一下之前見過的一個類似的問題,給定一個序列。問取若干個數能達到和k的方案數:DP[i][j]表示當前是序列中的第i個數(必須選),和能取到j的序列個數,這個問題這樣表示就是正確的了。
    為什麼會這樣呢?就是由於答案的推斷方式不同:第一個問題的答案推斷是,當前序列假設能取到若干個數使得和為k。那麼答案加一;第二個問題則是,假設有x種方案。從當前序列中取出若干個數使得和為k。那麼答案加x。也就是說。第一個問題的推斷根據是序列是否滿足,第二個則是取出來的集合是否滿足。而上述DP的方案事實上就是在選擇集合中的元素,由於DP[i][j]表示i必須選,也就是在集合中存在。

    那麼到此,怎樣推斷一個序列是否是滿足的呢:從左至右枚舉序列當前位置的值,那麼要求當前序列是否是滿足的也就是求和能否到k,那麼不可缺少的須要記錄一下當前序列所能到達的和都有誰。至此。就能夠用狀壓DP來解了。敘述一下二進位代表的意義:第一個1代表和為1。第二個1表示和為2……
    反思一下程式寫的時候的問題:沒實用滾動數組,導致錯了非常多次。

    因為這個題目的狀態轉移僅僅會向更大的狀態值(也能夠是自己)轉移。所以能夠不採用滾動數組,一維解決。

    可是這樣就須要額外注意一個問題。自己轉移到自己的問題。因為這裡理解的不是非常好。導致一直查不出來BUG。學習了。

const int MAXN = 21;int dp[1 << MAXN];int main(){    int T, n, sum, Max;    RI(T);    FE(kase, 1, T)    {        RIII(n, sum, Max);        int Min = min(sum, Max);        int all = 1 << sum;        CLR(dp, 0); dp[0] = 1;        REP(i, n)        {            FED(j, all - 1, 0)            {                if (dp[j] == 0)                    continue;                int x = dp[j];                for (int k = 1; k <= Min; k++)                {                    int nxt = j | ((j << k) & (all - 1)) | (1 << (k - 1));                    dp[nxt] += x;                    if (dp[nxt] >= MOD)                        dp[nxt] -= MOD;                }                if (Max - Min > 0)                    dp[j] = (dp[j] + 1LL * (Max - Min) * x) % MOD;            }        }        int ans = 0;        FF(i, 1 << (sum - 1), all)        {            ans += dp[i];            if (ans >= MOD)                ans -= MOD;        }        WI(ans);    }    return 0;}


用dp[1]表示0的方法,事實上不好。由於3(11)和2(10)表示的意義是一樣的,並且不含或者包括零(第一個一)沒有什麼意義
const int MAXN = 21;int dp[1 << MAXN];int main(){    int T, n, sum, Max;    RI(T);    FE(kase, 1, T)    {        RIII(n, sum, Max);        int Min = min(sum, Max);        int all = 1 << (sum + 1);        CLR(dp, 0); dp[1] = 1;        REP(i, n)        {            FED(j, all - 1, 1)            {                if (dp[j] == 0)                    continue;                int x = dp[j];                for (int k = 1; k <= Min; k++)                {                    int nxt = j | ((j << k) & (all - 1));                    dp[nxt] += x;                    if (dp[nxt] >= MOD)                        dp[nxt] -= MOD;                }                if (Max - Min > 0)                    dp[j] = (dp[j] + 1LL * (Max - Min) * x) % MOD;            }        }        int ans = 0;        FF(i, 1 << sum, all)        {            ans += dp[i];            if (ans >= MOD)                ans -= MOD;        }        WI(ans);    }    return 0;}



Our happy ending

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.