POJ 3046 -- Ant Counting (动态规划)
来源:互联网 发布:女朋友漂亮知乎 编辑:程序博客网 时间:2024/05/16 13:52
Description
This made for a large number of different sets of ants!
Being a bit mathematical, Bessie started wondering. Bessie noted that the hive has T (1 <= T <= 1,000) families of ants which she labeled 1..T (A ants altogether). Each family had some number Ni (1 <= Ni <= 100) of ants.
How many groups of sizes S, S+1, ..., B (1 <= S <= B <= A) can be formed?
While observing one group, the set of three ant families was seen as {1, 1, 2, 2, 3}, though rarely in that order. The possible sets of marching ants were:
3 sets with 1 ant: {1} {2} {3}
5 sets with 2 ants: {1,1} {1,2} {1,3} {2,2} {2,3}
5 sets with 3 ants: {1,1,2} {1,1,3} {1,2,2} {1,2,3} {2,2,3}
3 sets with 4 ants: {1,2,2,3} {1,1,2,2} {1,1,2,3}
1 set with 5 ants: {1,1,2,2,3}
Your job is to count the number of possible sets of ants given the data above.
Input
* Lines 2..A+1: Each line contains a single integer that is an ant type present in the hive
Output
Sample Input
3 5 2 312213
Sample Output
10
Hint
Three types of ants (1..3); 5 ants altogether. How many sets of size 2 or size 3 can be made?
OUTPUT DETAILS:
5 sets of ants with two members; 5 more sets of ants with three members
Source
USACO 2005 November Silver
问题描述: 第一行给出T A S B四个整数
T是指有T种不同的数,A是指这些数的总个数
S和B是指一个区间[S,B] 这个区间的每个整数值x代表这A个数的x个元素的子集
求: 从S到B这些子集的总个数的最后6位(MOD 1000,000)
实际上这就是一个多重集组合数问题:
有n种物品,第i种物品有ai个,不同种类的物品可以互相区分而相同种类的无法区分.
从这些物品中取出m个 有多少取法
每种物品就对应每种数字,相同的数字无法区分, 从这些数字种取S....B个 取法的总数%1000,000是多少
分析:
定义 dp[i+1][j] := 从前i种数取出j个数 共有多少种取法
可以这样考虑:
min(A[i],j)
dp[i+1][j] = Σ dp[i][j-k] * 1
k = 0
(也就是说 从前i-1种取出k个,剩下的从第i种取出,由于第i种的所有数都是相同的 无法区分 所以只有一种取法 在后面*1即可)
这样,枚举i,j,k 复杂度为O(nm²)
而
min(A[i],j) min(j-1,A[i])
Σdp[i][j-k] * 1 = Σdp[i][j-k-1] + dp[i][j](少的一项 k = 0) - dp[j-1-A[i]](多的一项 k = A[i]);
k=0 k=0
那么 把i代换成i+1 j-k代换为k
就得到 dp[i+1][j] = dp[i+1][j-1] + dp[i][j] - dp[j-1-A[i]](如果j-1 >=A[i])
这样复杂度为O(mn)
代码:
#include <cstdio>#include <cstring>#include <algorithm>#include <map>using namespace std;int t,a,s,b;int dp[5000 + 10][5000 + 10];int A[5000 + 10];map<int,int> m;int main(){scanf("%d %d %d %d",&t,&a,&s,&b);for(int i = 0;i<a;i++){int x;scanf("%d",&x);A[x-1]++;}//int cnt = 0;//for(map<int,int>::iterator it = m.begin();it!=m.end();it++)//{//A[cnt++] = it->second;//}for(int i = 0 ;i<=t;i++){dp[i][0] = 1;}for(int i = 0;i<t;i++){for(int j = 1;j<=b;j++){if(j - 1 - A[i] >=0){dp[i+1][j] = (dp[i+1][j-1] + dp[i][j] - dp[i][j-1-A[i]] + 1000000) % 1000000;}else{dp[i+1][j] = (dp[i+1][j-1] + dp[i][j]) % 1000000; }}}// dp[i+1][j] 从前i种选择出j个// min(A[i],j) min(j-1,A[i]) // = Σdp[i][j-k] * 1 = Σdp[i][j-k-1] + dp[i][j](少的一项 k = 0) - dp[j-1-A[i]](多的一项 k = A[i]); // k=0 k=0//主要是考虑如何降低复杂度 把Σ变为一维的加减运算 //代换 dp[i+1][j] = dp[i+1][j-1] + dp[i][j] - dp[j-1-A[i]] long long ans = 0;for(int i = s;i<=b;i++){ans = (ans + dp[t][i]) % 1000000;} printf("%lld\n",ans);}
- POJ 3046 -- Ant Counting (动态规划)
- POJ 3046 Ant Counting(“动态规划” 优化递推关系式)
- POJ 3046 Ant Counting
- POJ-3046-Ant Counting
- poj 3046 Ant Counting
- poj 3046 Ant Counting
- POJ 3046 Ant Counting
- ***POJ 3046 Ant Counting
- POJ 3046 Ant Counting dp
- 挑战练习题2.3动态规划 poj3046 Ant Counting dp
- POJ 3046 Ant Counting 简单DP
- POJ 3046 Ant Counting (dp)
- Ant Counting (poj 3046 分组背包)
- poj 3046 Ant Counting dp 优化
- [POJ 3046]Ant Counting[dp][优化]
- Poj 3046 Ant Counting【多重背包】
- poj 3046 Ant Counting (dp)
- POJ 3046 Ant Counting 已被翻译
- 聚类分析经典算法讲解及实现
- 线性求区间欧拉函数(顺便线性求区间内所有素数)(类似欧拉线性素数筛)
- 微调-模型
- ACM暑假集训日记 17.8.11
- BZOJ 2818 Gcd + spoj 4491(莫比乌斯反演 分块)
- POJ 3046 -- Ant Counting (动态规划)
- 一些java程序的运行结果
- .Net基础视频教程之6-函数
- 【暴力预处理+剪枝/bitset】Golf Bot UVALive
- fabric源码解析12——peer的MSP服务
- HPU 1410 QAQ & 火星情报局 (数学)
- Lesson02_C#基础_part02
- NSURLSession加载网络HTML数据
- 一步一步学Vue(七)