POJ 3046 Ant Counting(递推,和号优化)

计数类的问题,要求不重复,把每种物品单独考虑。

将和号递推可以把转移优化O(1)。

f[i = 第i种物品][j = 总数量为j] = 方案数

f[i][j] = sigma{f[i-1][j-k],(k = [0,min(j,c[i])])}
把和号展开 
f[i][j]  :    j-0,j-1,...,j-a[i]
f[i][j-1] :       j-1,j-2,...,j-a[i]-1
中间部分是一样的可以避免重复计算。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
//#include<bits/stdc++.h>
using namespace std;

int T, A, S, B;
const int maxt = 1e3+5, maxa = 1e5+5, mod = 1e6;
int f[2][maxa];
int c[maxt];

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    scanf("%d%d%d%d",&T,&A,&S,&B);
    for(int i = A; i--;){
        int x; scanf("%d",&x);
        c[x]++;
    }
    f[0][0] = f[1][0] = 1; //不选方案数为1
    for(int i = 1; i <= T; i++){
        int a = i&1, b = a^1;
        for(int j = 1; j <= B; j++){
            if(j-c[i]>0){
                f[a][j] = ( f[a][j-1] + f[b][j] - f[b][j-1-c[i]] ) % mod;
            }else {
                f[a][j] = ( f[a][j-1] + f[b][j] ) % mod;
            }
        }
    }
    int sum = 0, *F = f[T&1];
    for(int i = S; i <= B; i++){
        sum = (sum + F[i]) % mod;
    }
    printf("%d
",sum<0?sum+mod:sum);
    return 0;
}
原文地址:https://www.cnblogs.com/jerryRey/p/4887296.html