2012 Multi-University Training Contest 1
官方题解:2012 Multi-University Training Contest 1 Solution Report
1001 Clairewd’s message HDU4300 给出一个密码转换表和一个字符串(消息),这个消息由密文和原文组成,原文部分可能不完全,求最短可能的原文。 官方题解说要用到KMP,比赛的时候看到有那么多人过,根本没考虑复杂度,我是用给出的原文到密文的转换表求出密文的原文的转换表,然后随便搞搞就过了。
1002 Divide Chocolate HDU4301 把2*n的巧克力分为k块,问有多少种方法? f[i][j][0]表示前i行分成了j块,且第i行两格巧克力未被分开。 f[i][j][1]表示前i行分成了j块,且第i行两格巧克力属于不同的两块。 详见官方题解
#include
#include
#include
using namespace std;
const int MOD = 100000007;
int f[1010][2020][2];
int main()
{
int t, n, k;
cin >> t;
while (t--)
{
cin >> n >> k;
memset(f, 0, sizeof(f));
f[1][1][0] = f[1][2][1] = 1;
for (int i = 1; i < n; i++)
{
for (int j = 1; j <= k; j++)
{
f[i+1][j][0] = (f[i+1][j][0] + f[i][j][0] + f[i][j][1] * 2) % MOD;
f[i+1][j+1][0] = (f[i+1][j+1][0] + f[i][j][0] + f[i][j][1]) % MOD;
f[i+1][j][1] = (f[i+1][j][1] + f[i][j][1]) % MOD;
f[i+1][j+1][1] = (f[i+1][j+1][1] + f[i][j][0] * 2 + f[i][j][1] * 2) % MOD;
f[i+1][j+2][1] = (f[i+1][j+2][1] + f[i][j][0] + f[i][j][1]) % MOD;
}
}
cout << (f[n][k][0] + f[n][k][1]) % MOD << endl;
}
return 0;
}
1003 Holedox Eating HDU4302 每个时刻有两种动作,放食物和吃食物,吃的时候选择离当前位置最近的食物。 线段树,区间里记录最左面和最右面的食物位置,曾经把MAX设得太大导致RUNTIME ERROR(ACCESS_VIOLATION),花了好久才明白是哪里错了。。
#include
#include
#include
#include
using namespace std;
const int N = 100010;
struct Node
{
int l, r;
int leftmost, rightmost;
int count;
}tree[N * 4];
const int MAX = 1083647;
const int MIN = -MAX;
const int LEFT_TO_RIGHT = 0;
const int RIGHT_TO_LEFT = 1;
void build(int num, int l, int r)
{
tree[num].l = l;
tree[num].r = r;
tree[num].count = 0;
tree[num].leftmost = MAX;
tree[num].rightmost = MIN;
int mid = (l + r) / 2;
if (l < r)
{
build(num * 2, l, mid);
build(num * 2 + 1, mid + 1, r);
}
}
void insert(int num, int place)
{
if (tree[num].leftmost > place) tree[num].leftmost = place;
if (tree[num].rightmost < place) tree[num].rightmost = place;
++tree[num].count;
if (tree[num].l == tree[num].r) return;
int mid = (tree[num].l + tree[num].r) / 2;
if (place <= mid) insert(num * 2, place);
else insert(num * 2 + 1, place);
}
void remove(int num, int place)
{
--tree[num].count;
if (tree[num].l == tree[num].r)
{
// 这个位置没有蛋糕了,要恢复MAX和MIN
if (!tree[num].count)
{
tree[num].leftmost = MAX;
tree[num].rightmost = MIN;
}
}
else
{
int mid = (tree[num].l + tree[num].r) / 2;
if (place <= mid) remove(num * 2, place);
else remove(num * 2 + 1, place);
tree[num].leftmost = min(tree[num * 2].leftmost, tree[num * 2 + 1].leftmost);
tree[num].rightmost = max(tree[num * 2].rightmost, tree[num * 2 + 1].rightmost);
}
}
int getleftmost(int num, int l, int r)
{
//printf("%d %d %d %d %d\n", num, tree[num].l, tree[num].r, l, r);
if (tree[num].l == l && tree[num].r == r) return tree[num].leftmost;
int mid = (tree[num].l + tree[num].r) / 2;
if (r <= mid) return getleftmost(num * 2, l, r);
if (l > mid) return getleftmost(num * 2 + 1, l, r);
return min(getleftmost(num * 2, l, mid), getleftmost(num * 2 + 1, mid + 1, r));
}
int getrightmost(int num, int l, int r)
{
//printf("%d %d %d %d %d\n", num, tree[num].l, tree[num].r, l, r);
if (tree[num].l == l && tree[num].r == r) return tree[num].rightmost;
int mid = (tree[num].l + tree[num].r) / 2;
if (r <= mid) return getrightmost(num * 2, l, r);
if (l > mid) return getrightmost(num * 2 + 1, l, r);
return max(getrightmost(num * 2, l, mid), getrightmost(num * 2 + 1, mid + 1, r));
}
int main()
{
int t, l, n;
cin >> t;
for (int tcase = 1; tcase <= t; tcase++)
{
scanf("%d%d", &l;, &n;);
build(1, 0, l);
int temp;
int pos = 0;
long long ans = 0;
int direction;
for (int i = 0; i < n; i++)
{
scanf("%d", &temp;);
if (temp == 0) // 放蛋糕
{
int x;
scanf("%d", &x;);
insert(1, x);
}
else // 吃蛋糕
{
int rightmost = getrightmost(1, 0, pos);
int leftmost = getleftmost(1, pos, l);
if (rightmost == MIN && leftmost == MAX) continue;
int disleft = pos - rightmost; // 向左走的距离
int disright = leftmost - pos; // 向右走的距离
if (disleft < disright || (disleft == disright && direction == RIGHT_TO_LEFT))
{
// 注意如果蛋糕就在当前位置就不需要更新方向,下同
if (disleft != 0) direction = RIGHT_TO_LEFT;
remove(1, rightmost);
ans += disleft;
pos = rightmost;
}
else
{
if (disright != 0) direction = LEFT_TO_RIGHT;
remove(1, leftmost);
ans += disright;
pos = leftmost;
}
}
}
printf("Case %d: ", tcase);
cout << ans << endl;
}
return 0;
}
1009 Saving Princess claire_ HDU4308 把所有的P看成一个点(这里设为0),然后Dijkstra求最短路即可。
#include
#include
#include
using namespace std;
const int MAXN = 5010;
const int MAXM = 500010;
const int INF = 0x7f7f7f7f;
char map[MAXN][MAXN];
int head[MAXN];
int edgecount;
int r, c;
struct edge
{
int u, v, w;
int next;
}e[MAXM];
inline int getpos(int i, int j)
{
if (map[i][j] == 'P') return 0;
return i * c + j + 1;
}
// 添加一条从u到v的边
void addedge(int u, int v, int w)
{
e[edgecount].u = u;
e[edgecount].v = v;
e[edgecount].w = w;
e[edgecount].next = head[u];
head[u] = edgecount;
++edgecount;
}
int main()
{
int cost;
int start, end;
int dist[MAXN];
bool used[MAXN];
int maxn;
while (cin >> r >> c >> cost)
{
getchar();
for (int i = 0; i < r; i++) gets(map[i]);
edgecount = 0;
memset(head, -1, sizeof(head));
maxn = r * c;
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
{
if (map[i][j] == '#') continue;
int w;
if (map[i][j] == '*') w = cost;
else
{
w = 0;
if (map[i][j] == 'Y') start = getpos(i, j);
else if (map[i][j] == 'C') end = getpos(i, j);
}
if (i > 0 && map[i-1][j] != '#') addedge(getpos(i-1, j), getpos(i, j), w);
if (j > 0 && map[i][j-1] != '#') addedge(getpos(i, j-1), getpos(i, j), w);
if (i+1 < r && map[i+1][j] != '#') addedge(getpos(i+1, j), getpos(i,j), w);
if (j+1 < c && map[i][j+1] != '#') addedge(getpos(i, j+1), getpos(i,j), w);
}
}
memset(dist, 127, sizeof(dist));
dist[start] = 0;
int nodenow;
int mindis;
int ans = 0;
memset(used, 0, sizeof(used));
for (int i = 0; i <= maxn; i++)
{
mindis = INF;
for (int j = 0; j <= maxn; j++) if (!used[j] && dist[j] < mindis)
{
mindis = dist[j];
nodenow = j;
}
if (mindis == INF) break;
ans += mindis;
used[nodenow] = true;
if (nodenow == end) break;
int edgenumber = head[nodenow];
while (edgenumber != -1)
{
int newdis = mindis + e[edgenumber].w;
int newnode = e[edgenumber].v;
if (!used[newnode] && newdis < dist[newnode]) dist[newnode] = newdis;
edgenumber = e[edgenumber].next;
}
}
if (used[end]) cout << dist[end] << endl;
else puts("Damn teoy!");
}
return 0;
}
比赛的时候只做了1001,然后就没什么想法了。。那时候刚过一小时左右。然后去洗澡,还有点感冒了。当天早上还断网了,刚好用完一年的网费。1003想到是线段树不过不会写。
comments powered by Disqus