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("
");
}
}