比赛链接 http://acm.swjtu.edu.cn/JudgeOnline/showcontest?contest_id=1096
比赛统计
本场比赛总结
尽管这场比赛参加的人数不多,但是取得的效果我还是挺高兴的,这次的题目应该算是很常规的,每一道题都是考察了一方面的内容,所以我自己认为选题还是很好的,但还是有不足之处,就是缺乏考察数据结构和网络流的题目,等下一次的机会吧
解题分析
A
这一题是改编自2009年合肥赛区(中科大)现场赛的试题,其实我现在都不知道原题是怎么描述的,道听途说而已。方法很简单,打表,其实题目有透露信息的,比如到2009年才发现第47个梅森素数,可见,是可以打表通过的,不过我觉得下午过了的同学想必大多上网去找表了,是吗?“我自以为是”,如果你在合肥现场,你会怎么办呢?在英文版《具体数学》上Page109有梅森素数表可供参考,这题就不多说了。这里贴一个表吧
int A[36] = {2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, \ 127, 521, 607, 1279, 2203, 2281, 3217, 4253, \ 4423, 9689, 9941, 11213, 19937, 21701, 23209, \ 44497, 86243, 110503, 132049, 216091, 756839, \ 859433, 1257787, 1398269, 2976221};
B
这题是经典的树DP,改编自POJ,我们建立二维数组 dp[maxN][2],其中
dp[ i ][ 0 ],表示第 i 个人不参加活动时在树结构中最大的和谐值之和
dp[ i ][ 1 ],表示第 i 个人参加活动时在树结构中最大的和谐值之和
显然
dp[ i ][ 0 ] = sum { max(0, max(dp[ j ][0], dp[ j ][ 1 ] )) }
dp[ i ][ 1 ] = A[i] + sum { max(0, dp[ j ][ 0 ]) }
#include<cstdio> #include<cstring> #include<vector> #include<iostream> #include<algorithm> using namespace std; const int maxN = 1024; int N, x, y; int A[maxN]; vector<int> v[maxN]; int ans; int dp[maxN][2]; void dfs(int curNode) { dp[curNode][0] = 0; dp[curNode][1] = A[curNode]; ans = max(ans, A[curNode]); for(int j = 0; j < (int)v[curNode].size(); ++j) { if( dp[ v[curNode][j] ][0] == -1 ) { dfs( v[curNode][j] ); dp[curNode][1] += max(0, dp[v[curNode][j]][0]); dp[curNode][0] += max(0, max(dp[v[curNode][j]][0], dp[v[curNode][j]][1])); ans = max(ans, max(dp[curNode][0], dp[curNode][1])); } } } int main() { //freopen("data.in", "r", stdin); while( scanf("%d", &N) == 1 ) { for(int i = 1; i <= N && scanf("%d", A + i); ++i) v[i].clear(); for(int i = 1; i < N && scanf("%d %d", &x, &y); ++i) v[x].push_back(y), v[y].push_back(x); memset(dp, -1, sizeof(dp)); ans = 0; dfs(1); printf("%d\n", ans); } return 0; }
C
这题是很好的 dfs 搜索题,思想就是模拟栈了,这里注意到,因为最大才16,所以可以用位运算保存状态,在状态存储标记的时候,如果某一位为 ‘1’,表示离开,否则为进来,这样做的好处方便我们可以肯定,满足条件的最后一位一定是’1‘,而如果反过来表示,则最后一位一定是’0‘,但是,你并不知道它是不是表示离开这个状态。
#include<cstdio> #include<cstring> typedef long long llong; const int maxn = 20 + 2; int N, K; int A[maxn], L[maxn]; int tot_ans; void dfs(llong status, int posA, int posL, int posQ, int Q[]) { if(tot_ans == 16) return ; if(status & (1LL << (2 * N - 1))) { ++tot_ans; for(int i = 0; i < (N << 1); ++i) { if(status & (1LL << i) ) putchar('L'); else putchar('A'); } puts(""); return ; } // it has N A's and N L's, assume '1' -> L and '0' -> 'A' // if we can do 'A' if(posA < N) { int newQ[maxn << 1]; memcpy(newQ, Q, posQ * sizeof(int)); newQ[posQ] = A[posA]; dfs(status, posA + 1, posL, posQ + 1, newQ); } // if we can do 'L' if(posL < N && Q[posQ - 1] == L[posL]) { dfs(status | (1LL << (posA + posL)), posA, posL + 1, posQ - 1, Q); } } int main() { //freopen("data.in", "r", stdin); //freopen("data.out", "w", stdout); int Q[maxn << 1]; int sgn = 0; while( scanf("%d%d", &N, &K) == 2 ) { if( sgn ) puts(""); else sgn = 1; for(int i = 0; i < N; ++i) scanf("%d", A + i); for(int i = 0; i < N; ++i) scanf("%d", L + i); int idx_A = 0, idx_L = 0, idx_Q = 0; Q[idx_Q++] = A[idx_A++]; llong status = 0; tot_ans = 0; dfs(status, idx_A, idx_L, idx_Q, Q); if( tot_ans == 0 ) puts("Impossible"); } return 0; }
模拟题,这题没什么好说了,其实,一开始这一题我一直担心会出错,因为这题没有标程,测试数据是我手工出的,在 Python 测了好几遍,赛后才写了个标程,还好测试数据没有问题。
#include<cstdio> #include<cstring> const int maxN = 100 + 2; typedef long long i64d; char str[maxN]; int main() { //freopen("data.in", "r", stdin); static int idx = 0; bool sgn = 1, okX; i64d preVal = 0, X, Y, sgnX, sgnY; while( scanf("%s", str) == 1 ) { if( sgn ) printf("Case #%d:\n", ++idx), sgn = 0; if( !strcmp(str, "exit()")) { sgn = 1; preVal = 0; continue; } X = -1LL; Y = 0LL; okX = 0; sgnX = sgnY = 1LL; for(int i = 0; str[i]; ++i) { if( !okX ) { if( (str[i] == '+' || str[i] == '-') && X != -1LL ) { okX = 1; goto LP; } else if( str[i] == '+' ) continue; else if( str[i] == '-' ) sgnX *= -1LL; else if( str[i] == '_' ) X = preVal, okX = 1; else { if( X == -1LL ) X = 0; X = 10LL * X + (str[i] - '0'); } } else { LP: if( str[i] == '+' ) continue; else if( str[i] == '-' ) sgnY *= -1; else if( str[i] == '_' ) Y = preVal; else Y = 10LL * Y + (str[i] - '0'); } } //printf("%I64d + %I64d\n", X * sgnX, Y * sgnY); preVal = sgnX * X + sgnY * Y; printf("%I64d\n", preVal); } return 0; }
以上四题就是我自己想让大家做下的题目了,没有 AK 的。
本来以为黄海与老师也出了题目,后来告诉我说时间紧,就没有出题目,没办法,我总不能让大家就只做四道吧,所以选了3题E、F、G放上去了,这三题都是 csc2009 的比赛题,感觉挺好的,也推荐大家做做吧。
E
题目大意
struct Node { int x, y, pre; int s, step; Node(){} Node( int xx, int yy, int p, int ss, int st ):x(xx),y(yy),pre(p),s(ss),step(st){} };
struct element { char kind; int val; };
#include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxN = 1024; struct node { int x, y; node() {} node(int _x, int _y) : x(_x), y(_y) {} }; queue<node> q; int N; int dp[maxN][maxN]; void bfs() { while( !q.empty() ) q.pop(); dp[0][1] = 1; q.push( node(0, 1) ); node tmp, cur; int x, y; while( !q.empty() ) { tmp = q.front(); q.pop(); x = tmp.x, y = tmp.y; if( x - 1 >= 0 && !dp[x - 1][y] ) { dp[x - 1][y] = dp[x][y] + 1; cur = tmp; cur.x -= 1; q.push( cur ); } if( x + 1 < y && !dp[x + 1][y] ) { dp[x + 1][y] = dp[x][y] + 1; cur = tmp; cur.x += 1; q.push( cur ); } if( y - 1 > x && !dp[x][y - 1] ) { dp[x][y - 1] = dp[x][y] + 1; cur = tmp; cur.y -= 1; q.push( cur ); } if( y + 1 < N && !dp[x][y + 1] ) { dp[x][y + 1] = dp[x][y] + 1; cur = tmp; cur.y += 1; q.push( cur ); } if( 2 * y - x < N && !dp[y][2 * y - x] ) { dp[y][2 * y - x] = dp[x][y] + 1; cur.x = y; cur.y = 2 * y - x; q.push( cur ); } if( 2 * x - y >= 0 && !dp[2 * x - y][x] ) { dp[2 * x - y][x] = dp[x][y] + 1; cur.x = 2 * x - y; cur.y = x; q.push( cur ); } } } int main() { //freopen("data.in", "r", stdin); N = 1000; memset(dp, 0, sizeof(dp)); bfs(); int nT; scanf("%d", &nT); while( (nT --) > 0 ) { scanf("%d", &N); printf("%d\n", dp[N - 2][N - 1] - 1); } return 0; }
给定一点s,圆Ck,圆CI 。
问是否存在由s引出的一条射线,使得该射线经过Ck ,但不经过Cl 。(这里“经过”定义为相交或相切)
若设s即为坐标原点,则模型简化为:
是否存在由原点(0,0)引出的一条射线,使得该射线经过Ck ,但不经过CI 。