原题
题目分析
计数dp题,感觉其实也可以用组合数学做,但我太菜了,推不出通用公式.dp可以定义dp[i][j]为前i种选j个蚂蚁有多少种选法,然后递推公式如下,其中c[i]表示第i种的数量,
dp[i][j]=Σ(min(j,c[i]),k=0)dp[i-1][j-k].可以化简一下,dp[i][j]=∑(c[i],k=0)dp[i-1][j-1-k]+dp[i-1][j]-dp[i-1][j-1-c[i]],最后答案就是dp[t][s]+dp[t][s+1]+...+dp[t][b].然后这道题要状压,也就是i只有i和i-1,所以第一维可以压缩成i=1和i=0.
代码
1 #include <iostream> 2 #include <algorithm> 3 #include <utility> 4 #include <cstdio> 5 #include <cmath> 6 #include <cstring> 7 #include <string> 8 #include <vector> 9 #include <stack> 10 #include <queue> 11 #include <map> 12 #include <set> 13 14 using namespace std; 15 typedef long long LL; 16 const int INF_INT=0x3f3f3f3f; 17 const LL INF_LL=0x3f3f3f3f3f3f3f3f; 18 19 const int mod=1e6; 20 int num[2000]; 21 LL dp[2][200000]; 22 23 int main() 24 { 25 // freopen("black.in","r",stdin); 26 // freopen("black.out","w",stdout); 27 int t,a,s,b; 28 cin>>t>>a>>s>>b; 29 for(int i=0;i<a;i++) 30 { 31 int x; 32 scanf("%d",&x); 33 num[x]++; 34 } 35 int total=0; 36 for(int i=1;i<=t;i++) 37 { 38 total+=num[i]; 39 int now=i&1,last=!now; 40 dp[now][0]=dp[last][0]=1; 41 for(int j=1;j<=total;j++) 42 { 43 if(j-1-num[i]>=0) dp[now][j]=(dp[now][j-1]+dp[last][j]-dp[last][j-1-num[i]])%mod; 44 else dp[now][j]=(dp[now][j-1]+dp[last][j])%mod; 45 } 46 } 47 LL ans=0; 48 int res=t&1; 49 for(int i=s;i<=b;i++) ans=(ans+dp[res][i])%mod; 50 cout<<(ans+mod)%mod<<endl; 51 return 0; 52 }