题目链接:戳这里

题意:有A只蚂蚁,来自T个家族,每个家族有ti只蚂蚁。任取n只蚂蚁(S <= n <= B),求能组成几种集合?

这道题可以用dp或母函数求。

多重集组合数也是由多重背包问题拓展出来的一类经典问题,而此类问题也都可以用母函数求.

给大家讲2种方法:

①朴素方法:

状态:dp[i][j]:前i种中选j个可以组成的集合数

决策:第i种选k个,k<=cnt[i] && j-k>=0

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

复杂度为O(B*Σant[i])即O(B*A)也即O(A^2),虽说这题A最大可到1e5,但是实际数据水,能过

其实这个所谓的朴素dp算法就是母函数的算法.

附ac代码:

 1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 using namespace std;
5 typedef unsigned long long ll;
6 const int maxn = 1e3 + 10;
7 const int inf = 0x3f3f3f3f;
8 const int maxx = 1e5 + 10;
9 int dp[2][maxx];
10 int cnt[maxn];
11 int num[maxn];
12 const int mod = 1e6;
13 int main()
14 {
15 int t, a, s ,b, u;
16 scanf("%d %d %d %d", &t, &a, &s, &b);
17 for(int i = 1; i <= a; ++i)
18 {
19 scanf("%d", &u);
20 ++cnt[u];
21 }
22 //处理边界问题,当只有一种蚂蚁的时候,无论多少个蚂蚁,组成的集合都是1
23 for(int i = 0; i <= cnt[1]; ++i) // 这里从0开始赋值是为了后面当j- k = 0时dp[][j-k]=1
24 dp[1][i] = 1;
25 for(int i = 2; i <= t; ++i)
26 {//这里j=0依然是处理边界,比如dp[3][1] = dp[2][0] + dp[2][1]
27 for(int j = 0; j <= b; ++j)
28 {
29 for(int k = 0; k <= min(j, cnt[i]); ++k)
30 {
31 dp[i & 1][j] = (dp[i & 1][j] + dp[(i & 1) ^ 1][j - k]) % mod;
32
33 }
34 // printf("%d %d %d\n", dp[i&1][j], i, j);
35 }
36 memset(dp[(i & 1) ^ 1], 0, sizeof(dp[(i & 1) ^ 1]));
37 }
38 int ans = 0;
39 for(int i = s; i <= b; ++i)
40 {
41 ans = (ans + dp[t & 1][i]) % mod;
42 }
43 printf("%d\n", ans);
44 return 0;
45 }

②优化递推式

状态:dp[i][j]:前i种中选j个可以组成的集合数

决策:第i种不选或者至少选一个

转移: dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-cnt[i]-1] (j-cnt[i]-1>=0)

优化思路:

根据①可以知道

dp[i][j]=∑{k=0~min(j,cnt[i])} dp[i][j-k]

所以dp[i][j-1]=∑(k=0~min(j-1,cnt[i])} dp[i][j-1-k]

二者之间的关系是:

dp[i][j]=dp[i][j-1]+dp[i][j-1]-dp[i-1][j-cnt[i]-1] 即得出优化的转移方程.

通俗来说,就是从前i种中取j个只与从前i种中取j-1个有两种情况不同,其他都是一样的.

这样就省去了大量的重复运算.

复杂度为O(T*B)

附ac代码:

 1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 using namespace std;
5 typedef unsigned long long ll;
6 const int maxn = 1e3 + 10;
7 const int inf = 0x3f3f3f3f;
8 const int maxx = 1e5 + 10;
9 int dp[2][maxx];
10 int cnt[maxn];
11 int num[maxn];
12 const int mod = 1e6;
13 int main()
14 {
15 int t, a, s ,b, u;
16 scanf("%d %d %d %d", &t, &a, &s, &b);
17 for(int i = 1; i <= a; ++i)
18 {
19 scanf("%d", &u);
20 ++cnt[u];
21 }
22 //处理边界问题,当只有一种蚂蚁的时候,无论多少个蚂蚁,组成的集合都是1
23 for(int i = 0; i <= cnt[1]; ++i) // 这里从0开始赋值是为了后面当j- k = 0时dp[][j-k]=1
24 dp[1][i] = 1;
25 for(int i = 2; i <= t; ++i)
26 {//这里j=0依然是处理边界,比如dp[3][1] = dp[2][0] + dp[2][1]
27 for(int j = 0; j <= b; ++j)
28 {
29 dp[i & 1][j] = (dp[i & 1][j] + dp[(i & 1) ^ 1][j] + dp[i & 1][j - 1])%mod;
30 if(j - 1 - cnt[i] >= 0)
31 dp[i & 1][j] = (dp[i & 1][j] - dp[(i & 1) ^ 1][j - 1 - cnt[i]] + mod)%mod;//+mod防止负数
32 // printf("%d %d %d\n", dp[i&1][j], i, j);
33 }
34 memset(dp[(i & 1) ^ 1], 0, sizeof(dp[(i & 1) ^ 1]));
35 }
36 int ans = 0;
37 for(int i = s; i <= b; ++i)
38 {
39 ans = (ans + dp[t & 1][i])%mod;
40 }
41 printf("%d\n", ans);
42 return 0;
43 }

参考博客:戳这里

poj-3046 Ant Counting【dp】【母函数】的更多相关文章

  1. poj 3046 Ant Counting (DP多重背包变形)

    题目:http://poj.org/problem?id=3046 思路: dp [i] [j] :=前i种 构成个数为j的方法数. #include <cstdio> #include ...

  2. POJ 3046 Ant Counting DP

    大致题意:给你a个数字,这些数字范围是1到t,每种数字最多100个,求问你这些a个数字进行组合(不包含重复),长度为s到b的集合一共有多少个. 思路:d[i][j]——前i种数字组成长度为j的集合有多 ...

  3. poj 3046 Ant Counting

    Ant Counting Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4982   Accepted: 1896 Desc ...

  4. poj 3046 Ant Counting(多重集组合数)

    Ant Counting Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) Total ...

  5. POJ 3046 Ant Counting ( 多重集组合数 && 经典DP )

    题意 : 有 n 种蚂蚁,第 i 种蚂蚁有ai个,一共有 A 个蚂蚁.不同类别的蚂蚁可以相互区分,但同种类别的蚂蚁不能相互区别.从这些蚂蚁中分别取出S,S+1...B个,一共有多少种取法. 分析 :  ...

  6. poj 3046 Ant Counting——多重集合的背包

    题目:http://poj.org/problem?id=3046 多重集合的背包问题. 1.式子:考虑dp[ i ][ j ]能从dp[ i-1 ][ k ](max(0 , j - c[ i ] ...

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

    计数类的问题,要求不重复,把每种物品单独考虑. 将和号递推可以把转移优化O(1). f[i = 第i种物品][j = 总数量为j] = 方案数 f[i][j] = sigma{f[i-1][j-k], ...

  8. 【BZOJ1630/2023】[Usaco2007 Demo]Ant Counting DP

    [BZOJ1630/2023][Usaco2007 Demo]Ant Counting 题意:T中蚂蚁,一共A只,同种蚂蚁认为是相同的,有一群蚂蚁要出行,个数不少于S,不大于B,求总方案数 题解:DP ...

  9. POJ Ant Counting DP

    dp[i][j]表示前i种蚂蚁组成元素个数为j的集合有多少种. 则dp[i][j] = dp[i-1][j] + dp[i-1][j-1] + ... + dp[i-1][ max(0,j-a[i]) ...

  10. 【POJ - 3046】Ant Counting(多重集组合数)

    Ant Counting 直接翻译了 Descriptions 贝西有T种蚂蚁共A只,每种蚂蚁有Ni只,同种蚂蚁不能区分,不同种蚂蚁可以区分,记Sum_i为i只蚂蚁构成不同的集合的方案数,问Sum_k ...

随机推荐

  1. fsutil比较有用的几个命令

    Fsutil:fsinfo 主要由专业支持者使用.列出所有驱动器,查询驱动器类型,查询卷信息,查询特定的 卷信息或文件系统统计信息. 语法参数 drives 列出计算机中所有的驱动器. drivety ...

  2. LSTM+CRF进行序列标注

    为什么使用LSTM+CRF进行序列标注 直接使用LSTM进行序列标注时只考虑了输入序列的信息,即单词信息,没有考虑输出信息,即标签信息,这样无法对标签信息进行建模,所以在LSTM的基础上引入一个标签转 ...

  3. FPGA仿真的概念及语法特点

    以下是特权同学<FPGA设计+实战演练>书中的描述:      一个正规的设计需要花费在验证上的工作量,往往可能会占到整个开发流程的70%左右.验证通常分为仿真验证和板机验证.      ...

  4. 网络基础知识之Cisco

    2021-01-2313:35:21 大家好,我是新手,刚学完Cisco协议,以后,我会每天都会给大家一些学习笔记 和一些学习心得,这方面不会的可以找我.qq2934896930. 网络的定义: 计算 ...

  5. Swagger-UI展示接口

    简单介绍API的管理工具Swagger的UI模块. 简介:swagger ui就是一个能整合到项目中让api的注释能够生成到一个网页上.能简单测试和给前端看. 第一步:添加引用 打开NuGet程序包管 ...

  6. Redis 实战 —— 09. 实现任务队列、消息拉取和文件分发

    任务队列 P133 通过将待执行任务的相关信息放入队列里面,并在之后对队列进行处理,可以推迟执行那些耗时对操作,这种将工作交给任务处理器来执行对做法被称为任务队列 (task queue) . P13 ...

  7. timeout of 20000ms exceeded

    前端:axios请求超时 axios 中有两种超时错误,一种是 HTTP 的超时,另一种是你自定的超时时间. 请求多次,设置拦截器 ---在main.js设置全局的请求次数,请求的间隙 推荐解决方法: ...

  8.  打开APP  04 | 网络通信:RPC框架在网络通信上更倾向于哪种网络IO模型? 2020-02-26 何小锋

     打开APP  04 | 网络通信:RPC框架在网络通信上更倾向于哪种网络IO模型? 2020-02-26 何小锋

  9. Flash 终将谢幕:微软将于年底停止对 Flash 的支持

    近日,微软宣布将于今年 12 月终止对 Adobe Flash Player 的支持,届时,微软旗下所有浏览器都将无法使用 Flash,Adobe 也不会在今年 12 月后发布安全更新.早在 2017 ...

  10. 编译安装 codeblocks 20.03 mips64el

    期末考试要用哦,不然谁会愿意去踩这么多坑. qaq 龙梦 Fedora28 中有 codeblocks 17.12,但是 Ctrl-v 粘贴会闪退,导致压根不能用.Bing了一下发现这其实是 code ...