1. 程式人生 > >POJ 3046

POJ 3046

bar str copy %d name print 復制代碼 ant else

題目大意:螞蟻牙黑,螞蟻牙紅:有A只螞蟻,來自T個家族,分別記為ant[i]個。同一個家族的螞蟻長得一樣,但是不同家族的螞蟻牙齒顏色不同。任取n只螞蟻(S <= n <= B),求能組成幾種集合?

狀態:dp[i][j]:前i種中選j個可以組成的種數

決策:第i種選k個,k<=ant[i] && j-k>=0

轉移:dp[i][j]=Σdp[i-1][j-k]

技術分享圖片
#include<stdio.h>
#include<string.h>
int dp[1005][10050];
int num[10050];
int main(){
    int n,m,a,b,x;
    while(scanf("%d%d%d%d",&n,&m,&a,&b)!=EOF){
        memset(num,0,sizeof(num));
        for(int i=0;i<m;i++){
            scanf("%d",&x);
            num[x]++;
        }
        memset(dp,0,sizeof(dp));
        for(int i=0;i<=num[1];i++) dp[1][i]=1;
        for(int i=2;i<=n;i++){
            for(int j=0;j<=b;j++){
                for(int k=0;k<=num[i];k++){
                    if(j>=k) {
                    dp[i][j]+=dp[i-1][j-k];
                    dp[i][j]%=1000000;
                    }
                }
            }
        }
        int ans=0;
        for(int i=a;i<=b;i++){
            ans+=dp[n][i];
            ans%=1000000;
        }
        printf("%d\n",ans);
    }
    return 0;
}
技術分享圖片

還有一種

dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-ant[i]-1]

技術分享圖片
#include<iostream>
using namespace std;
#define MOD 1000000
int T, A, S, B;
int ant[1005];
int dp[2][100000];
int ans;
int main()
{
    scanf("%d%d%d%d", &T, &A, &S, &B);
    for (int i = 1; i <= A; i++)
    {
        int aa;
        scanf("%d", &aa);
        ant[aa]++;
    }
    dp[0][0] = dp[1][0] = 1;
    for (int i = 1; i <= T; i++)
        for (int j = 1; j <= B; j++)
            if (j - ant[i] - 1 >= 0) dp[i % 2][j] = (dp[(i - 1) % 2][j] + dp[i % 2][j - 1] - dp[(i - 1) % 2][j - ant[i] - 1] + MOD) % MOD;      //在取模時若出現了減法運算則需要先+Mod再對Mod取模,防止出現負數(如5%4-3%4為負數)
            else dp[i % 2][j] = (dp[(i - 1) % 2][j] + dp[i % 2][j - 1]) % MOD;
    for (int i = S; i <= B; i++)
        ans = (ans + dp[T % 2][i]) % MOD;
    printf("%d\n", ans);
    return 0;
}
技術分享圖片

POJ 3046