1. 程式人生 > >attack on titans(動態規劃遞推,限制條件,至少轉至多方法,進擊的巨人)

attack on titans(動態規劃遞推,限制條件,至少轉至多方法,進擊的巨人)

amp build ever ber die namespace 沒有 tin per

題目意思:

給n個士兵排隊,每個士兵三種G、R、P可選,求至少有m個連續G士兵,最多有k個連續R士兵的排列的種數。

原題

Attack on Titans

Time Limit: 2 Seconds Memory Limit: 65536 KB Over centuries ago, mankind faced a new enemy, the Titans. The difference of power between mankind and their newfound enemy was overwhelming. Soon, mankind was driven to the brink of extinction. Luckily, the surviving humans managed to build three walls: Wall Maria, Wall Rose and Wall Sina. Owing to the protection of the walls, they lived in peace for more than one hundred years.

But not for long, a colossal Titan appeared out of nowhere. Instantly, the walls were shattered, along with the illusory peace of everyday life. Wall Maria was abandoned and human activity was pushed back to Wall Rose. Then mankind began to realize, hiding behind the walls equaled to death and they should manage an attack on the Titans.

So, Captain Levi, the strongest ever human being, was ordered to set up a special operation squad of N people, numbered from 1 to N. Each number should be assigned to a soldier. There are three corps that the soldiers come from: the Garrison, the Recon Corp and the Military Police. While members of the Garrison are stationed at the walls and defend the cities, the Recon Corps put their lives on the line and fight the Titans in their own territory. And Military Police serve the King by controlling the crowds and protecting order. In order to make the team more powerful, Levi will take advantage of the differences between the corps and some conditions must be met.

The Garrisons are good at team work, so Levi wants there to be at least M Garrison members assigned with continuous numbers. On the other hand, members of the Recon Corp are all elite forces of mankind. There should be no more than K Recon Corp members assigned with continuous numbers, which is redundant. Assume there is unlimited amount of members in each corp, Levi wants to know how many ways there are to arrange the special operation squad.

Input


There are multiple test cases. For each case, there is a line containing 3 integers N (0 < N < 1000000), M (0 < M < 10000) and K (0 < K < 10000), separated by spaces. Output
One line for each case, you should output the number of ways mod 1000000007.

Sample Input

3 2 2

Sample Output
5
//首先感謝MartaYang的詳細博文讓我搞懂這題
//https://blog.csdn.net/MartaYang/article/details/77175488
/*
思路:
1(至少化為至多):至少化為至多,這樣可以使問題簡單化,
比如說從10個人中至少挑3人=10人至多挑十人(無限制的總方案數)-10人至多挑6人
技術分享圖片


那麽這題同理有:
至少m個連續G士兵=至多n個連續G士兵-至多m-1個連續G士兵

準備一個數組,縱行代表處理到第幾位放哪個士兵的方案數,橫行代表這三個兵種各自的方案數
先處理一下邊緣條件,然後
假設G至多u個連續,R至多v個連續(剛剛已經把至少問題轉換為至多問題了)
對於G:
如果現在當前行i<=u,那麽可以隨便排列
技術分享圖片


如果當前行i=u+1,加完各種情況後要減去一種情況,就是前面u個全是g的情況,
因為是一種情況,所以減1
技術分享圖片


如果當前行>u+1,那麽加完各種情況後要-a[i-u-2]-a[i-u-3]; 即減去第i-u-2位不是G而中間其他位置都是G的情況,這樣可以避免第i個放下去後產生u+1個連續 有人會問為什麽不是-1-1 因為這其實是-a[i-u-2]*1-a[i-u-3]*1 那個*1其實是*中間全是G,這卻時常是1種,所以-a[i-u-2]-a[i-u-3] 技術分享圖片


用這種方法,i>u+1位以後,就不可能出現連續數超過u,因為通過減方案減去了可能出現問題的地方
*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn=10e6+10;
ll a[maxn][4];//定義一個數組,a[i][1]代表第i位選的總方案數G士兵,
//同理a[i][2]代表第i位選R士兵的總方案數,a[i][1]代表第i位選P士兵的總方案數,
ll n,m,k;//最少m個連續G,最多k個連續R
ll mod=1000000007;//定義模,題目要求取模
ll solve(ll u,ll v)//準備一個函數算方案
{
    if(u==0) a[1][1]=0; else a[1][1]=1;//為G士兵賦初始值,要考慮當連續的要求為0的情況
    //a[1][1]表示第一位選G的方案數
    //a[2][1]表示第二位選G並且包含前面的總方案數
    if(v==0) a[1][2]=0;else a[1][2]=1;//v和u差不多
    a[1][3]=1;//第三種士兵沒有限制,直接賦初值為1
    for(ll i=2;i<=n;i++)//枚舉每一個位置,從2到n
    {
        a[i][3]=a[i-1][1]+a[i-1][2]+a[i-1][3];
        //第三種士兵的方案數等於前一個位置三種方案數相加
        if(i<=u) a[i][1]=(a[i-1][1]+a[i-1][2]+a[i-1][3])%mod;
        else if(i==u+1) a[i][1]=(a[i-1][1]+a[i-1][2]+a[i-1][3]-1)%mod;
        else a[i][1]=(a[i-1][1]+a[i-1][2]+a[i-1][3]-a[i-u-1][2]-a[i-u-1][3])%mod;

        if(i<=v) a[i][2]=(a[i-1][1]+a[i-1][2]+a[i-1][3])%mod;
        else if(i==v+1) a[i][2]=(a[i-1][1]+a[i-1][2]+a[i-1][3]-1)%mod;
        else a[i][2]=(a[i-1][1]+a[i-1][2]+a[i-1][3]-a[i-u-1][1]-a[i-u-1][3])%mod;
    }
    return (a[n][1]+a[n][2]+a[n][3])%mod;//把方案數return出去

}

int main()
{
    cin>>n>>m>>k;
    //最多n個連續G,最多k個連續R --減去-- 最少m-1個連續G,最多k個連續R
    cout<<((solve(n,k)-solve(m-1,k))%mod+mod)%mod<<endl;
    return 0;
}

attack on titans(動態規劃遞推,限制條件,至少轉至多方法,進擊的巨人)