1. 程式人生 > >擺花(NOIP2012 普及組第三題)

擺花(NOIP2012 普及組第三題)

數據規模 .cn ostream .com col tdi int png namespace

問題描述   小明的花店新開張,為了吸引顧客,他想在花店的門口擺上一排花,共m盆。通過調查顧客的喜好,小明列出了顧客最喜歡的n種花,從1到n標號。為了在門口展出更多種花,規定第i種花不能超過ai盆,擺花時同一種花放在一起,且不同種類的花需按標號的從小到大的順序依次擺列。
  試編程計算,一共有多少種不同的擺花方案。 輸入格式   第一行包含兩個正整數n和m,中間用一個空格隔開。
  第二行有n個整數,每兩個整數之間用一個空格隔開,依次表示a1、a2、……an。 輸出格式   輸出只有一行,一個整數,表示有多少種方案。註意:因為方案數可能很多,請輸出方案數對1000007取模的結果。 樣例輸入 2 4
3 2 樣例輸出
2 輸入輸出樣例說明   有2種擺花的方案,分別是(1,1,1,2), (1,1,2,2)。括號裏的1和2表示兩種花,比如第一個方案是前三個位置擺第一種花,第四個位置擺第二種花。 數據規模和約定   對於20%數據,有 0<n≤8,0<m≤8,0≤ai≤8;
  對於50%數據,有0<n≤20,0<m≤20,0≤ai≤20;
  對於100%數據,有0<n≤100,0<m≤100,0≤ ai≤100。

分析

動態規劃:題目要求花必須按從小到大的順序擺放,並且同種類的花必須挨著放,則題目就簡單多了。

a[i]表示第i種花最多使用的盆數
f[i][j]表示前i種花,擺j盆的擺放方案數。對於第i種花可以使用0、1、2...a[i]盆,對應的前i-1種花擺放的盆數為j-0、j-1、j-2、...j-a[i]
即f[i][j]=f[i-1][j]+f[i-1][j-1]+f[i-1][j-2]+...+f[i-1][j-a[i]] =f[i-1][j-k](0<=k<=a[i],j>=k)
方程寫出來後,最關鍵的就是賦初始值

初始值f[1][0]=1,f[1][1]=1,...f[1][a[1]]=1;
初始值f[i][0]=1;(1<=i<=n)

以題中樣例為例:

2 4 3 2 很顯然f[1][1]=f[1][2]=f[1][3]=1; f[2][1]=2,前2種花,放一盆,則有1,2兩種方法。 又f[2][1]=f[1][0]+f[1][1]=f[1][0]+1可以推出f[1][0]=1; 同樣的方法可以推出f[2][0]=f[3][0]=...=f[n][0]=1; (f[2][2]=f[1][0]+f[1][1]+f[1][2], f[2][3]=f[1][1]+f[1][2]+f[1][3], f[2][4]=f[1][2]+f[1][3]+f[1][2]) 技術分享
#include<iostream>

using namespace std;

int n, m , a[120] = {0}, f[120][120] = {0};
const int mod = 1000007;

int main()
{
    freopen("flower.in","r",stdin);
    freopen("flower.out","w",stdout);
    cin >> n >> m;
    for(int i = 1;i <= n;i++)
    {
        cin >> a[i];
    }
    f[0][0] = 1;
    for(int i = 1;i <= n;i++)
    {
        for(int j = 0;j <= m;j++)
        {
            for(int k = 0;k <= a[i];k++)
            {
                if(k <= j)
                {
                    f[i][j] = (f[i][j]+f[i-1][j-k])%mod;
                }
            }
        }
    }
    cout << f[n][m] << endl;
    return 0;
}

擺花(NOIP2012 普及組第三題)