A. HDU 5999 The Third Cup is Free
简单模拟。
B. HDU 6000 Wash
n 件衣服, m 个洗衣机,k 个烘干机。每个洗衣机和烘干机需要不同的时间。问 n 件衣服洗完 + 烘干最小时间。
看做两部:洗 + 烘干,用洗需要时间长的去配烘干需要时间短的,所有衣服取max。
优先队列维护,取最小的,加上时长再放进去。
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; typedef long long LL; typedef pair<LL, int> pr; int main() { int t; scanf("%d", &t); for (int ca = 1; ca <= t; ca++) { int n, m, k; scanf("%d%d%d", &n, &m, &k); priority_queue<pr, vector<pr>, greater<pr> > q1, q2; LL x; for (int i = 1; i <= m; i++) scanf("%lld", &x), q1.push(pr(x, x)); for (int i = 1; i <= k; i++) scanf("%lld", &x), q2.push(pr(x, x)); vector<LL> a, b; LL ans = 0; for (int i = 1; i <= n; i++) { pr tmp = q1.top(); q1.pop(); a.push_back(tmp.first); q1.push(pr(tmp.first + tmp.second, tmp.second)); } int len = a.size(); for (int i = 1; i <= n; i++) { pr tmp = q2.top(); q2.pop(); q2.push(pr(tmp.first + tmp.second, tmp.second)); ans = max(ans, a[len-i] + tmp.first); } printf("Case #%d: %lld ", ca, ans); } }
C. HDU 6001 Mr.Panda and Survey
容斥 + DFS
D. HDU 6002 Game Leader
优先队列贪心
E. HDU 6003 Problem Buyer
贪心。
F. HDU 6004 Periodical Cicadas
DP预处理 + exgcd
G. HDU 6005 Pandaland
给你一些边,求最小环。边数 <= 4000。
枚举每条边,设其长度为 inf 后求两端点的最短路,最后再把答案加上原本的边长。
最短路用堆优化的Dijkstra,若 dis + 边长 > ans直接停止,否则会TLE。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <map> #include <queue> #include <set> using namespace std; typedef pair<int, int> pr; const int INF = 0x3f3f3f3f; const int maxn = 4000 + 100; int n; int sz = 0, tot; int v[2*maxn], last[2*maxn], nxt[2*maxn], lo[2*maxn]; int dis[2*maxn], vis[2*maxn], ans; void build(int x,int y,int z) { sz++; v[sz] = y, nxt[sz] = last[x], last[x] = sz, lo[sz] = z; sz++; v[sz] = x, nxt[sz] = last[y], last[y] = sz, lo[sz] = z; } int Dijkstra(int s, int t, int extr) { for (int i = 1; i <= tot; i++) dis[i] = INF, vis[i] = 0; dis[s] = 0; priority_queue<pr, vector<pr>, greater<pr> > q; q.push(pr(0, s)); while(!q.empty()) { pr node = q.top(); q.pop(); int x = node.second, length = node.first; if (length + extr > ans) break; if (vis[x]) continue; vis[x] = 1; for (int i = last[x]; i; i = nxt[i]) if (dis[v[i]] > dis[x] + lo[i]) { dis[v[i]] = dis[x] + lo[i]; q.push(pr(dis[v[i]], v[i])); } } return dis[t]; } int main() { int t; scanf("%d", &t); for (int ca = 1; ca <= t; ca++) { tot = sz = 0; memset(last, 0, sizeof(last)); map<pr, int> mp; scanf("%d", &n); int x1, x2, y1, y2, x; for (int i = 1; i <= n; i++) { scanf("%d%d%d%d%d", &x1,&y1,&x2,&y2,&x); if (mp[pr(x1, y1)] == 0) mp[pr(x1, y1)] = ++tot; if (mp[pr(x2, y2)] == 0) mp[pr(x2, y2)] = ++tot; build(mp[pr(x1, y1)], mp[pr(x2, y2)], x); } ans = INF; for (int i = 1; i <= sz; i += 2) { int x = v[i], y = v[i+1]; int tmplen = lo[i]; lo[i] = lo[i+1] = INF; ans = min(ans, Dijkstra(x, y, tmplen) + tmplen); lo[i] = lo[i+1] = tmplen; } if (ans >= INF) ans = 0; printf("Case #%d: %d ", ca, ans); } }
H. HDU 6006 Engineer Assignment
n 个工程,每个工程都有一些需求的领域。 m 个工程师,每个工程师有几个擅长的领域,且仅能被分配到一个项目。
当且仅当一些工程师满足了项目的全部需求领域,这个项目才会被完成。问最多可以完成几个项目。
n,m都很小,预处理出每个项目需要的工程师,状态压缩 + 背包。
(x & j) == x时,证明 j 包含 x; j ^ x 就是 j 代表的集合减去 x 代表的集合。
#include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <set> using namespace std; const int maxn = 10 + 10; vector<int> a[maxn], b[maxn]; int e[maxn][1 << 11]; int dp[maxn][1 << 11]; int main() { int t; scanf("%d", &t); for (int ca = 1; ca <= t; ca++) { int n, m, k, x; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) a[i].clear(); for (int j = 1; j <= m; j++) b[j].clear(); memset(e, 0, sizeof(0)); for (int i = 1; i <= n; i++) { scanf("%d", &k); for (int j = 1; j <= k; j++) scanf("%d", &x), a[i].push_back(x); } for (int i = 1; i <= m; i++) { scanf("%d", &k); for (int j = 1; j <= k; j++) scanf("%d", &x), b[i].push_back(x); } for (int i = 1; i <= n; i++) { set<int> st; for (int j = 0; j < a[i].size(); j++) st.insert(a[i][j]); for (int j = 1; j < (1<<m); j++) { set<int> s2; for (int k = 0; k < m; k++) if (j & (1<<k)) for (int l = 0; l < b[k+1].size(); l++) s2.insert(b[k+1][l]); set<int> :: iterator it; int flag = 1; for (it = st.begin(); it != st.end(); it++) if (!s2.count(*it)) { flag = 0; break; } e[i][j] = flag; } } for (int i = 1; i <= n; i++) for (int j = 1; j < (1<<m); j++) { dp[i][j] = dp[i-1][j]; for (int x = 1; x < (1<<m); x++) if (e[i][x] && (x&j) == x) dp[i][j] = max(dp[i][j], dp[i-1][j^x] + 1); } int ans = 0; for (int i = 1; i < (1<<m); i++) ans = max(ans, dp[n][i]); printf("Case #%d: %d ", ca, ans); } }
I. HDU 6007 Mr. Panda and Crystal
制造所有宝石都是可以用花费来衡量的。最短路跑出所有宝石的最小制作费用,然后完全背包就可以了。
一种宝石可以更新花费,当且仅当有一种配方的总花费小于它的花费。可以用vector记录配方信息,然后再用一个vector记录每个宝石的配方下标。
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> using namespace std; typedef long long LL; const int maxn = 300 + 10; const int maxm = 400010; const int INF = 0x3f3f3f3f; int dis[maxn], weg[maxn]; int vis[maxn]; vector<int> a[maxn], aid[maxn], sum[maxn], tp[maxn]; int v[2*maxm], last[2*maxm], nxt[2*maxm]; int dp[maxm]; int n, m, k, sz; void build(int x, int y) { sz++; v[sz] = y, nxt[sz] = last[x], last[x] = sz; } bool relax(int x, int y) { int siz = tp[y].size(), res = INF; for (int i = 0; i < siz; i++) { int to = tp[y][i], s = aid[to].size(), ans = 0, flag = 0; for (int j = 0; j < s; j++) { int ad = aid[to][j], sm = sum[to][j]; if (dis[ad] == INF) { flag = 1; break; } ans += dis[ad] * sm; } if (flag == 0) res = min(res, ans); } if (dis[y] > res) return dis[y] = res, true; return false; } void SPFA() { queue<int> q; memset(vis, 0, sizeof(vis)); for (int i = 1; i <= n; i++) if (dis[i] != INF) q.push(i), vis[i] = 1; while(!q.empty()) { int x = q.front(); q.pop(); for (int i = last[x]; i; i = nxt[i]) if (relax(x, v[i]) && !vis[v[i]]) vis[v[i]] = 1, q.push(v[i]); vis[x] = 0; } } int main() { int t; scanf("%d", &t); for (int ca = 1; ca <= t; ca++) { sz = 0; memset(last, 0, sizeof(last)); scanf("%d%d%d", &m, &n, &k); for (int i = 0; i < max(n, k); i++) aid[i].clear(), sum[i].clear(), tp[i].clear(); //死在这里的clear了。不能只循环到n,因为k可能大于n。 for (int i = 1; i <= n; i++) { int typ; scanf("%d", &typ); typ == 1 ? scanf("%d", &dis[i]):dis[i] = INF; scanf("%d", &weg[i]); } for (int i = 1; i <= k; i++) { int x, s, fr, d; scanf("%d%d", &x, &s); for (int j = 1; j <= s; j++) { scanf("%d%d", &fr, &d); build(fr, x); aid[i].push_back(fr), sum[i].push_back(d); } tp[x].push_back(i); } SPFA(); memset(dp, 0, sizeof(dp)); for (int i = 1; i <= n; i++) for (int j = dis[i]; j <= m; j++) dp[j] = max(dp[j], dp[j-dis[i]]+weg[i]); printf("Case #%d: %d ", ca, dp[m]); } }
J. HDU 6008 Worried School
题意复杂。
set判重即可,分别求出两个名次。注意 region + final <= G-1 时是 "ADVANCED!" 。
K. HDU 6009 Lazors
模拟。
L. HDU 6010 Daylight Saving Time
模拟。只要处理出second Sunday in March 和 first Sunday in November 是几号就可以了。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int mon[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int run(int x) { if (x%4 == 0 && x%100 != 0) return 1; if (x%400 == 0) return 1; return 0; } int day(int y, int m, int d) { int sum = 0; for (int i = 2007; i < y; i++) sum += 365 + run(i); for (int i = 1; i < m; i++) { sum += mon[i]; if (run[y] && i == 2) sum++; } sum += d; return sum%7; } int main() { int t; scanf("%d", &t); for (int ca = 1; ca <= t; ca++) { int y, m, d, h, mi, s; scanf("%d-%d-%d %d:%d:%d", &y,&m,&d,&h,&mi,&s); int pst = 0, pdt = 0; int times = 0, Nov = 1, Mar = 1; for (int i = 1; i <= 30; i++) { if (!day(y, 11, i)) times++; if (times == 2) { Nov = i; break; } } times = 0; for (int i = 1; i <= 30; i++) { if (!day(y, 11, i)) times++; if (times == 2) { Mar = i; break; } } printf("Case #%d: ", ca); if (m > 3 && m < 11) printf("PDT"); if (m > 11 || m < 3) printf("PST"); if (m == 3) { if (h >= 3) printf("PDT"); else if (h < 2) printf("PST"); else printf("Neither"); } else if (m == 11) { if (h >= 2) printf("PST"); else if (h < 1) printf("PDT"); else printf("Both"); } printf(" "); } }