刷題——Ant Counting POJ - 3046

/*
給四個數:T,A,S,B表示,有A個數,數從1-T,現求集合元素個數爲S-B的組合和,只用輸出6位
假設給定4個數1,2,3,4每個數只有1個
        0       1       2                   3               4
0       1       0       0                   0               0
1       1       1       0                   0               0
2       1       1,2     12                  0               0
3       1       1,2,3   12,13,23            123             0
4       1       1,2,3,4 12,13,23,14,24,34   123,124,134,234 1234
dp[i][j]表示前i個數組合成j長度的個數
很明顯的可以看出,當長度小於等於第i個數的個數時dp[i][j]=dp[i][j-1]+dp[i-1][j]
大於時dp[i][j]=dp[i-1][j]+(dp[i][j-1]-dp[i-1][j-1-t_ni[i]])
大於時有衝突的部分要捨去,畫表格和可以看出要捨去的部分時dp[i-1][j-1-t_ni[i]]帶來的
dp[i-1][j]爲前i-1個數組合成j長度的個數,對於同一個長度,這部分是垂直往下累加的


所以方程爲:
dp[i][j]={
        dp[i][j-1]+dp[i-1][j]:t_ni[i]<=j
        dp[i-1][j]+(dp[i][j-1]-dp[i-1][j-1-t_ni[i]]
}


dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1-t_ni[i]]+mod)%mod; 這裏去掉衝突的部分會出現負數
我不是很清楚是在什麼情況下出現的
*/
#include <stdio.h>
#include <string.h>
int t,a,s,b;
int t_ni[1010];
int dp[1010][100010];
const int mod=1000000;
int main(){
    while(scanf("%d %d %d %d",&t,&a,&s,&b)!=EOF){
        memset(t_ni,0,sizeof(t_ni));
        int x;
        for(int i=0;i<a;i++){
            scanf("%d",&x);
            t_ni[x]++;
        }
        for(int i=0;i<=t;i++){
            dp[i][0]=1;
        }
        for(int i=1;i<=t;i++){
            for(int j=1;j<=b;j++){
                if(j<=t_ni[i]){
                    dp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;
                }
                else{
                    dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1-t_ni[i]]+mod)%mod;
                }
            }
        }
        int num=0;
        for(int i=s;i<=b;i++){
            num=(num+dp[t][i])%mod;
        }
        printf("%d\n",num);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章