POJ 3616 Milking Time
大意:贝茜是一个勤劳的牛。事实上,她如此专注于最大化她的生产力,于是她决定安排下一个N(1≤N≤1,000,000)小时(方便地标记为0…N-1),以便她生产尽可能多的牛奶。
农民约翰有一个M(1≤M≤1,000)可能重叠的间隔列表,他可以在那里进行挤奶。每个区间我有一个起始小时(0≤starting_houri≤N),一个结束小时(starting_houri <ending_houri≤N),以及相应的效率(1≤efficiencyi≤1,000,000),表示他可以从中获取多少加仑的牛奶。贝西在那段时间。 Farmer John分别在开始时间和结束时间开始时开始和停止挤奶。在挤奶时,Bessie必须在整个间隔内挤奶。
尽管贝茜有其局限性。在任何间隔期间挤奶后,她必须休息R(1≤R≤N)小时才能再次开始挤奶。鉴于Farmer Johns的间隔清单,确定Bessie在N小时内可以产生的最大牛奶量。
提醒:休息时间,如:第3小时结束工作,休息2小时,第5小时就可以开始工作。
思路:
首先按照结束时间进行排序,设res[i]
表示工作到第i
时刻,最大的收益
如果此时i
为其中一个结束时间,则res[i] = max(res[i], res[i - 1], res[max(0, start - j)] + eff)
表示i
时刻的最大收益来源是上一个时刻的工资,或之前计算出来的工资(因为给的数据可能在同一时间结束的有好几组,所以需要和原来的值进行比较),或者是开始工作前r
小时的收益加上这次工作的收益。
如果不是结束时间,则收益和前一时刻是一样的,因为这个时间段要不就是没工作,要不就是还没工作完,都是没有收益的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std ;const int M = 1010 ;const int N = 1000010 ;int n, m, r;struct node { int start; int end; int eff; }; bool cmp (const node &a, const node &b) { if (a.end == b.end) { return a.start < b.start; } return a.end < b.end; } node cows[M]; int res[N];void solve () { int j = 0 ; int i = 1 ; while (i <= n && j < m) { if (i < cows[j].end) { res[i] = max(res[i], res[i - 1 ]); } else { res[i] = max(res[i], max(res[i - 1 ], res[max(0 , cows[j].start - r)] + cows[j].eff)); j++; continue ; } i++; } printf ("%d\n" , max(res[i], res[n])); } int main () { while (scanf ("%d%d%d" , &n, &m, &r) != EOF) { for (int i = 0 ; i < m; i++) { scanf ("%d%d%d" , &cows[i].start, &cows[i].end, &cows[i].eff); } sort(cows, cows + m, cmp); memset (res, 0 , sizeof (res)); solve(); } }
POJ 3280 Cheapest Palindrome
大意:给定一个字符串S,字符串S的长度为M(M≤2000),字符串S所含有的字符的种类的数量为N(N≤26),然后给定这N种字符Add与Delete的代价,求将S变为回文串的最小代价和。
思路:
改天打算看看关于回文串的一些解题思路(先记下来,免得忘记
设dp[i][j]
表示,S[i]-S[j]
变成回文串最少需要的代价,cost[i]
表示删除或添加S[i]
的较小代价。因为dp[i][j]
表示的是将[i, j]
范围内变成回文串,而处理两侧的一个字符,删除和添加是一样的性质,所以只需要求代价小的那个操作即可。
如果S[i] == S[j]
, 则dp[i][j] = dp[i + 1][j - 1]
否则dp[i][j] = min(dp[i + 1][j] + cost[S[i] - 'a'], dp[i][j - 1] + cost[S[j] - 'a'])
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <cstdio> #include <cstring> #include <iostream> const int INF = 99999999 ;const int N = 2005 ;using namespace std ;int cost[60 ];int dp[N][N];int main () { int n, m, x, y; char s[N], e; while (scanf ("%d%d" , &n, &m) != EOF) { scanf ("%s" , s); memset (cost, 0 , sizeof (cost)); for (int i = 0 ; i < n; i++) { cin >> e >> x >> y; cost[e - 'a' ] = min(x, y); } memset (dp, 0 , sizeof (dp)); for (int k = 1 ; k < m; k++) { for (int i = 0 , j = k; j < m; i++, j++) { dp[i][j] = INF; if (s[i] == s[j]) { dp[i][j] = dp[i + 1 ][j - 1 ]; } else { dp[i][j] = min(dp[i][j], dp[i + 1 ][j] + cost[s[i] - 'a' ]); dp[i][j] = min(dp[i][j], dp[i][j - 1 ] + cost[s[j] - 'a' ]); } } } printf ("%d\n" , dp[0 ][m - 1 ]); return 0 ; } }
POJ 1743 Coins
大意:给定N种硬币,其中第 i 种硬币的面值为Ai,共有Ci个。从中选出若干个硬币,把面值相加,若结果为S,则称“面值S能被拼成”。求1~M之间能被拼成的面值有多少个。
dp[j]
表示结果j
能否被拼凑
sum[j]
表示在使用价值为A[1]~A[i]
的币拼凑结果为j - A[i]
的时候,用的价值为A[i]
的金币的个数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <iostream> #include <cstdio> #include <cstring> using namespace std ;const int N = 110 ;const int M = 100010 ;int n, m;int A[N], C[N];bool dp[M]; int sum[M];void solve () { memset (dp, 0 , sizeof (dp)); int res = 0 ; dp[0 ] = 1 ; for (int i = 0 ; i < n; i++) { memset (sum, 0 , sizeof (sum)); for (int j = A[i]; j <= m; j++) { if (!dp[j] && dp[j - A[i]] && sum[j - A[i]] < C[i]) { dp[j] = 1 ; sum[j] = sum[j - A[i]] + 1 ; res++; } } } printf ("%d\n" , res); } int main () { while (scanf ("%d%d" , &n, &m) && n) { for (int i = 0 ; i < n; i++) { scanf ("%d" , &A[i]); } for (int i = 0 ; i < n; i++) { scanf ("%d" , &C[i]); } solve(); } }
POJ 3046 Ant Counting
大意:给出T种元素,每个元素个数为tot[i]
,询问从所有元素中挑出k个组成的不同集合数目sum[k]
,k∈[S,B]
,ans=SUM{sum[k] | S<=k<=B}
为了防止超出内存,使用了滚动数组。
d[i][j]
表示用i
种元素,组成j
的方案数
dp[i][j] = sum(dp[i - 1][k]), k从max(0, j - num[i])到j
即用i
种类元素组成j
实际上就是用i - 1
种元素组成j
然后再加上用i
元素拼凑最后
(这个还有待优化一下…)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std ;const int T = 100010 ;const int N = 1010 ;const int MAXN = 1000000 ;int t, a, s, b;int num[N];int dp[2 ][T];void solve () { dp[0 ][0 ] = 1 ; for (int i = 1 ; i <= t; i++) { for (int j = 0 ; j <= a; j++) { int sum = 0 ; for (int k = max(0 , j - num[i]); k <= j; k++) { sum = (sum + dp[(i - 1 ) % 2 ][k]) % MAXN; } dp[i % 2 ][j] = sum; } } int total = 0 ; for (int i = s; i <= b; i++) { total = (total + dp[t % 2 ][i]) % MAXN; } printf ("%d\n" , total); } int main () { while (scanf ("%d%d%d%d" , &t, &a, &s, &b) != EOF) { memset (num, 0 , sizeof (num)); for (int i = 0 ; i < a; i++) { int n; scanf ("%d" , &n); num[n]++; } memset (dp, 0 , sizeof (dp)); solve(); } }
POJ 3181 Dollar Dayz
这是一个划分数问题,即求一个数N能被1-T的数划分的方案数
dp[i][j]
表示用i~i
的数拼凑成j
的方案数
则dp[i][j] = dp[i - 1][j] + dp[i][j - i]
即要不就是用前1 ~ i - 1
的数拼凑j
,或者用1 ~ i
的数拼凑j - i
注意到这个二维其实可以化简成一维的问题,因为在计算dp[i][j]
只用到了上一行的第j
位和已经计算过的当前行的j - 1
位,所以该式子也可以写成dp[j] = dp[j] + dp[j - i]
但是这里需要注意的就是,这个值有可能过大,并且用long long都不能表示,但是使用高精度又太花费时间,因此这里采用dp1
来表示高位,dp2
来表示低位
所以dp[j] = dp1[j] * mod + dp1[j] + dp2[j - i] * mod + dp2[j - i]
dp2[j] = (dp1[j] + dp2[j - i]) % mod
dp1[j] = dp1[j] + dp2[j - i] + (dp1[j] + dp2[j - i]) / mod
因为计算之后dp1[j]
会发生变化,所以必须dp2[j]
先计算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std ;typedef long long LL;LL dp1[1005 ], dp2[1005 ], mod; int N, K;int main () { scanf ("%d%d" , &N, &K); mod = 1 ; for (int i = 1 ; i <= 18 ; i++) { mod *= 10 ; } dp2[0 ] = 1L L; for (int i = 1 ; i <= K; i++) { for (int j = i; j <= N; j++) { dp1[j] += dp1[j - i] + (dp2[j] + dp2[j - i]) / mod; dp2[j] = (dp2[j] + dp2[j - i]) % mod; } } if (dp1[N]) { cout << dp1[N]; } cout << dp2[N]; return 0 ; }
明天写一下今晚npy教的Hash~~