最近做题比较散漫,无脑。中间打了个校赛,弱弱的水了几题,然后就挂机了,最后一个半小时都在酱油,结果也不是很好。
中间大概有三场bc是爆零了,快浅绿了。cf 打了两场只有only div2的,还好比较容易涨,大号终于紫了。
Hdu Dp入门题总结,时间隔的比较长,大概有一个月了。。网上写的也比较详细,这6题还是记忆犹新的,其他的就不说了。
Cstructing Roads http://acm.hdu.edu.cn/showproblem.php?pid=1025
以前做过,按照一维排序,另一位用nlogn的LIS做法做。写的时候,发现线段树可以搞,按照其中一维排序以后,
在另一维上建树,每个点的值表示这个点之前的最多连线对包括这个点。更新的时候,找到这个点之前的最大值,然后
最大值加一更新到这个点上。线段树维护一下区间最大值。
/* *********************************************** Author : 一个西瓜 Mail : [email protected] Created Time : 2015-04-14 20:32:08 Problem : Constructing Roads In JGShining's Kingdom ************************************************ */ #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 //typedef __int64 LL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 const int maxn = 555555 + 10; int sum[maxn << 2]; void build(int l, int r, int rt) { sum[rt] = 0; if (l == r) return; int mid = (l + r) >> 1; build(lson); build(rson); } void up(int rt) { sum[rt] = max(sum[rt << 1], sum[rt << 1 | 1]); } void update(int key, int add, int l, int r, int rt) { if (l == r){ sum[rt] = add; return; } int mid = (l + r) >> 1; if (key <= mid) update(key, add, lson); else update(key, add, rson); up(rt); } int ask(int L, int R, int l, int r, int rt) { if (L <= l&&r <= R) return sum[rt]; int ans = -1; int mid = (l + r) >> 1; if (L <= mid) ans = max(ans, ask(L, R, lson)); if (R > mid) ans = max(ans, ask(L, R, rson)); return ans; } struct Node { int x; int y; }node[maxn]; int cmp(const Node &a, const Node &b) { if (a.x == b.x) return a.y < b.y; return a.x < b.x; } int main() { int n; int Icase = 0; while (cin >> n){ build(1, n, 1); for (int i = 1; i <= n; i++) scanf("%d%d", &node[i].x, &node[i].y); int Max = -1; sort(node + 1, node + 1 + n, cmp); for (int i = 1; i <= n; i++){ int t = ask(1, node[i].y, 1, n, 1); Max = max(Max, t + 1); update(node[i].y, t + 1, 1, n, 1); } //if (Icase) putchar('\n'); Icase++; printf("Case %d:\n", Icase); if (Max == 1) printf("My king, at most %d road can be built.\n", Max); else printf("My king, at most %d roads can be built.\n", Max); cout << endl; } return 0; }
Humble Numbers http://acm.hdu.edu.cn/showproblem.php?pid=1058
dp[n] = min(2*dp[i],3*dp[j],5*dp[k],7*dp[l]; 哪个最小, 哪个下标加一
/* *********************************************** Author : wtmlon Mail : [email protected] Created Time : 2015-03-27 19:42:09 Problem : Humble Numbers ************************************************ */ #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 //typedef __int64 LL; int f[111111]; int Min(int a, int b, int c, int d) { return min(min(a, b), min(c, d)); } int gao(int a, int b, int c, int d) { int a1 = f[a] * 2; int b1 = f[b] * 3; int c1 = f[c] * 5; int d1 = f[d] * 7; int t = Min(a1, b1, c1, d1); if (t == a1) return 1; if (t == b1) return 2; if (t == c1) return 3; return 4; } int main() { int n; int l2 = 1, l3 = 1, l5 = 1, l7 = 1; f[1] = 1; for (int i = 2; i <= 5842; i++){ int t = gao(l2, l3, l5, l7); if (t == 1){ int k = f[l2] * 2; if (k == f[i - 1]) { i--; l2++; continue; } f[i] = k; l2++; } if (t == 2){ int k = f[l3] * 3; if (k == f[i - 1]){ i--; l3++; continue; } f[i] = k; l3++; } if (t == 3){ int k = f[l5] * 5; if (k == f[i - 1]){ i--; l5++; continue; } f[i] = k; l5++; } if (t == 4){ int k = f[l7] * 7; if (k == f[i - 1]){ i--; l7++; continue; } f[i] = k; l7++; } } while (cin >> n&&n){ int k = n%100; if(k>=10&&k<=20){ printf("The %dth humble number is %d.\n",n,f[n]); } else{ k = k%10; if(k==1){ printf("The %dst humble number is %d.",n,f[n]); } else if(k==2){ printf("The %dnd humble number is %d.",n,f[n]); } else if(k==3){ printf("The %drd humble number is %d.",n,f[n]); } else printf("The %dth humble number is %d.",n,f[n]); cout<<endl; } } return 0; }
Fast Food http://acm.hdu.edu.cn/showproblem.php?pid=1227
搜的题解发现中位数距离最短,然后就能写了。顺便学了下带权中位数,就是一样的,把权值当成个数,然后按照大小排序过以后,权值从头开始加找到恰好大于所有权值和w的一半时的那个点,这个点到其他所有点的带权曼哈顿距离和最小。可以求多维的情况,因为是曼哈顿距离,所以不同维度的距离和是相互独立的。
/* *********************************************** Author : 一个西瓜 Mail : [email protected] Created Time : 2015-04-19 14:47:52 Problem : Fast Food ************************************************ */ #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 //typedef __int64 LL; int a[222]; int sum[222]; int dp[222][222]; int cost(int x, int y) { int t = (x + y) / 2; int ans = 0; for (int i = x; i <= y; i++){ ans += abs(a[i] - a[t]); } return ans; } int main() { int Icase = 0; int n, k; while (cin >> n >> k, n || k){ for (int i = 1; i <= n; i++){ scanf("%d", &a[i]); } printf("Chain %d\n", ++Icase); for (int i = 1; i <= n;i++) for (int j = 1; j <= k; j++) dp[i][j] = INF; /*for (int i = 1; i <= n; i++){ for (int j = i + 1; j <= n; j++){ int ans = 0; for (int k = i + 1; k < j; k++){ ans += min(a[k] - a[i], a[j] - a[k]); } cost[i][j] = ans; } }*/ /*for (int i = 1; i <= n; i++){ int ans = 0; for (int j = 1; j < i; j++){ ans += a[i] - a[j]; } dp[i][1] = ans; }*/ for (int i = 1; i <= n; i++) dp[i][1] = cost(1, i); for (int i = 2; i <= k; i++){ for (int j = 1; j <= n; j++){ for (int l = i - 1; l < j; l++){ dp[j][i] = min(dp[j][i], dp[l][i - 1] + cost(l+1,j)); } } } printf("Total distance sum = %d\n\n", dp[n][k]); } return 0; }
Regular Words http://acm.hdu.edu.cn/showproblem.php?pid=1502
抄了个大数模板卡过, dp[i][j][k] = dp[i-1][j][k] + dp[i][j-1][k] + dp[i][j][k-1];
/* *********************************************** Author : 一个西瓜 Mail : [email protected] Created Time : 2015-04-20 10:12:04 Problem : Regular Words ************************************************ */ #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 //typedef __int64 LL; typedef long long LL; //套了个大数模板卡过。 struct BigInt { const static int mod = 10000; const static int DLEN = 4; int a[30], len; BigInt() { memset(a, 0, sizeof(a)); len = 1; } BigInt(int v) { memset(a, 0, sizeof(a)); len = 0; do { a[len++] = v%mod; v /= mod; } while (v); } BigInt(const char s[]) { memset(a, 0, sizeof(a)); int L = strlen(s); len = L / DLEN; if (L%DLEN)len++; int index = 0; for (int i = L - 1; i >= 0; i -= DLEN) { int t = 0; int k = i - DLEN + 1; if (k < 0)k = 0; for (int j = k; j <= i; j++) t = t * 10 + s[j] - '0'; a[index++] = t; } } BigInt operator +(const BigInt &b)const { BigInt res; res.len = max(len, b.len); for (int i = 0; i <= res.len; i++) res.a[i] = 0; for (int i = 0; i < res.len; i++) { res.a[i] += ((i < len) ? a[i] : 0) + ((i < b.len) ? b.a[i] : 0); res.a[i + 1] += res.a[i] / mod; res.a[i] %= mod; } if (res.a[res.len] > 0)res.len++; return res; } BigInt operator *(const BigInt &b)const { BigInt res; for (int i = 0; i < len; i++) { int up = 0; for (int j = 0; j < b.len; j++) { int temp = a[i] * b.a[j] + res.a[i + j] + up; res.a[i + j] = temp%mod; up = temp / mod; } if (up != 0) res.a[i + b.len] = up; } res.len = len + b.len; while (res.a[res.len - 1] == 0 && res.len > 1)res.len--; return res; } void output() { printf("%d", a[len - 1]); for (int i = len - 2; i >= 0; i--) printf("%04d", a[i]); printf("\n"); } }dp[61][61][61]; int main() { int n; BigInt gg(1); dp[0][0][0] = dp[0][0][0] + gg; for (int i = 1; i <= 60; i++){ for (int j = 0; j <= i; j++){ for (int k = 0; k <= j; k++){ if (i - 1 >= j) dp[i][j][k] =dp[i][j][k] + dp[i - 1][j][k]; if (j - 1 >= k) dp[i][j][k] =dp[i][j][k] + dp[i][j - 1][k]; if (k - 1 >= 0) dp[i][j][k] =dp[i][j][k] + dp[i][j][k - 1]; } } } while (cin >> n){ dp[n][n][n].output(); cout << endl; } return 0; }
Doing Homework Again http://acm.hdu.edu.cn/showproblem.php?pid=1789
按截止日期从小到大排个序,然后dp[i][j] 表示第i个任务当前时间为j的最多得的分
dp[i][j] = max(dp[i-1][j] , dp[i-1][j-1] + val[i]); j这天做不做第i个任务中间的最多得分.
拿总的分数减下,就是最少的要扣的分数。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 //typedef __int64 LL; const int maxn = 1111; struct Node { int x; int y; }node[maxn]; int cmp(const Node &a, const Node &b) { if (a.x == b.x) return a.y < b.y; return a.x < b.x; } int dp[maxn][maxn]; int main() { int T,n; cin >> T; while (T--){ cin >> n; int sum = 0; int Max = -1; for (int i = 1; i <= n; i++) scanf("%d", &node[i].x); for (int i = 1; i <= n; i++) scanf("%d", &node[i].y), sum += node[i].y; sort(node + 1, node + 1 + n, cmp); memset(dp,0,sizeof(dp)); for (int i = 1; i <= n; i++){ for (int j = 1; j <= node[i].x; j++){ dp[i][j] = max(dp[i - 1][j - 1] + node[i].y, dp[i - 1][j]); Max = max(dp[i][j], Max); } } cout << sum - Max << endl; } return 0; }
Employment Planning http://acm.hdu.edu.cn/showproblem.php?pid=1158
我猜测能雇佣人数的取值范围就是每个月要求的人数的取值,所以最后就是一个n^2的dp,然后就过了。
/* *********************************************** Author : 一个西瓜 Mail : [email protected] Created Time : 2015-04-15 20:53:26 Problem : Employment Plannin ************************************************ */ #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 //typedef __int64 LL; int a[100]; int dp[30][30]; int main() { int n; int hire, salary, fire; while (scanf("%d", &n) && n){ scanf("%d%d%d", &hire, &salary, &fire); for (int i = 0; i <= n; i++) for (int j = 0; j <= n; j++) dp[i][j] = INF; dp[0][0] = 0; a[0] = 0; int Min = INF; for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i <= n; i++){ for (int j = 0; j <= n; j++){ if (a[j] < a[i]) continue; for (int k = 0; k <= n; k++){ int b = a[j]; int c = a[k]; if (b >= c){ dp[i][j] = min(dp[i][j], dp[i - 1][k] + b*salary + (b - c)*hire); } else{ dp[i][j] = min(dp[i][j], dp[i - 1][k] + (c - b)*fire + b*salary); } //if (i == 2 && j == 2) printf("%d %d %d %djiji\n", b,c,dp[i][j],dp[i-1][]); } //cout << i << " " << j << " " << dp[i][j] << endl; } } for (int i = 1; i <= n; i++) Min = min(Min, dp[n][i]); cout << Min << endl; } return 0; }