2012年"新秀杯"程序设计比赛——现场决赛参考题解

引言:比较简略,还请见谅!能力有限,难免有错,敬请不吝指导 ^_^ ~


比赛链接:http://acm.swjtu.edu.cn/JudgeOnline/showcontest?contest_id=1131


比赛对象:大一、大二


比赛时间:2012年11月18日 12:00——17:00


参考题解:


【A题:推箱子】

对箱子进行广搜,判断箱子的当前状态是否合法,判断合法的方式是,判断人能否从原状态到达箱子的“后面”。


测试数据:

输入

22
6 4
0 0 0 1 0 0
0 0 2 4 0 0
0 1 1 1 0 0
0 0 3 0 0 0
6 5
0 0 0 0 0 0
4 0 2 0 0 0
1 1 1 1 1 0
0 0 0 0 0 0
3 0 0 0 0 0
5 6
0 0 0 0 0
0 2 1 1 0
0 0 1 0 0
0 0 0 0 1
0 1 1 0 1
0 4 0 0 3
7 5
1 1 4 1 0 0 0
1 1 2 1 0 0 0
3 0 0 0 0 0 0
0 1 0 1 0 0 0
0 0 0 1 0 0 0
6 6
0 4 1 0 0 0
0 2 0 0 0 0
1 0 1 0 1 1
0 0 1 0 3 0
1 0 0 0 0 0
0 0 0 0 0 0
5 6
0 0 0 3 0
0 1 4 0 1
0 1 2 1 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
6 6
0 0 0 0 1 0
0 4 0 1 0 0
0 0 0 1 0 0
0 0 1 0 2 0
0 1 0 0 3 0
0 0 1 0 0 0
6 6
0 0 0 0 1 0
0 2 0 1 0 0
0 0 0 1 0 0
0 0 1 0 4 0
0 1 0 0 3 0
0 0 1 0 0 0
5 3
4 0 0 0 0
0 2 0 0 0
0 0 0 0 3
5 3
4 0 0 0 0
2 0 0 0 0
0 0 0 0 3
5 3
4 2 0 0 0
1 1 1 0 1
0 0 3 0 0
5 3
0 1 0 0 0
4 2 0 0 0
0 1 3 1 0
6 6
0 0 0 0 0 3
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 2 0 0 0 0
4 0 0 0 0 0
6 6
0 0 0 0 0 4
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 2 0 0 0 0
3 0 0 0 0 0
6 6
0 0 1 0 0 0
0 0 1 0 0 0
0 0 1 0 0 0
4 2 3 0 0 0
0 0 1 0 0 0
0 0 1 0 0 0
6 6
0 0 0 1 0 0
0 0 0 1 0 0
0 0 0 1 0 0
0 0 0 3 2 4
0 0 0 1 0 0
0 0 0 1 0 0
6 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
1 1 1 3 1 1
0 0 0 2 0 0
0 0 0 4 0 0
6 6
0 0 0 4 0 0
0 0 0 2 0 0
1 1 1 3 1 1
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
5 5
0 0 0 0 0
4 2 0 1 1
0 1 0 0 0
1 0 0 0 3
1 0 0 0 0
5 3
4 0 0 0 0
2 0 0 0 0
0 0 0 0 3
7 5
1 1 4 1 0 0 0
1 1 2 1 0 0 0
3 0 0 0 0 0 0
0 1 0 1 0 0 0
0 0 0 1 0 0 0
6 6
0 0 0 0 0 3
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 2 0 0 0 0
4 0 0 0 0 0

输出

Case #1: 6
Case #2: -1
Case #3: 7
Case #4: 11
Case #5: 9
Case #6: 3
Case #7: -1
Case #8: -1
Case #9: 4
Case #10: -1
Case #11: -1
Case #12: 4
Case #13: 8
Case #14: 2
Case #15: 1
Case #16: 1
Case #17: 1
Case #18: 1
Case #19: 5
Case #20: -1
Case #21: 11
Case #22: 8

【B题:五子棋】

首先,通过给定的当前状态,判断是哪位棋手下;然后,去枚举判断每一位空位,判断是否可以赢得游戏。


测试数据:

输入:

11
_______________
_______________
_______________
__________b____
_________w_____
______wbw______
____bbwwbb_____
__bbwbwbbwb____
___wwbbwbw_____
_bwwwwbwwwb____
_bwwwwbwbww____
___wbbw_bbbw___
____wbbb_______
______bb_______
_______________

_______________
_______________
_______________
_______________
_______________
___bbbb________
__w____________
__w____________
__w____________
_______________
_______________
_______________
_______________
_______________
_______________

_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________

________w______
_____w__b______
____wbb_bbw____
_______wb______
________w______
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________

________b______
_____wwwb______
_____wbbbb_____
_______wb______
________w______
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________

_______________
_______________
_______________
w______________
_w______w______
__b____b_______
___b__b________
___wb_b________
___wb__________
__wbw_b________
__www__b_______
_______________
_______________
_______________
_______________

_______________
bbbbw__________
bbbbw__________
wwwwbw_________
____wbw________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________
_______________

_______________
_______________
_______________
_______________
______w________
______w________
______w________
______w________
_______________
_____b_________
___b_b_b_______
_______________
_______________
_______________
_______________

_______________
_______________
____w__________
_____w_________
______w________
_______________
________w______
_______________
_______________
_____b_________
___bbbwb_______
_____b_________
_______________
_______________
_______________

_______________
_______________
____________w__
_______________
__________w____
_________w_____
________w______
_______________
_______________
_____b_________
___bbbwb_______
_____b_________
_______________
_______________
_______________

_______________
_______________
_______________
______b________
______b________
_______________
______b________
___ww_w________
_______________
_______________
_______________
_______________
_______________
_______________
_______________

输出

Case #1: Yes
Case #2: No
Case #3: No
Case #4: Yes
Case #5: No
Case #6: Yes
Case #7: No
Case #8: No
Case #9: Yes
Case #10: Yes
Case #11: No

【C题:24点】

枚举数字和运算符,计算是否存在某一数学表达式值为24即可,可通过回溯法求解。


测试数据:

输入

30
4 10 4 10
5 5 5 A
2 7 9 9
2 10 10 10
3 3 3 3
3 3 3 4
3 3 3 5
3 3 3 6
3 3 3 7
3 3 3 8
3 3 3 9
3 3 3 10
3 3 4 4
3 3 4 10
3 3 5 5
3 3 5 8
3 3 6 6
3 3 7 10
3 3 8 8
3 3 9 9
3 3 10 10
3 4 6 7
3 4 8 8
3 4 9 10
3 5 5 5
3 5 5 10
3 5 7 7
3 5 8 10
A A J J
A 2 Q Q

输出

Case #1: Yes
Case #2: Yes
Case #3: No
Case #4: No
Case #5: Yes
Case #6: Yes
Case #7: Yes
Case #8: Yes
Case #9: Yes
Case #10: Yes
Case #11: Yes
Case #12: Yes
Case #13: Yes
Case #14: No
Case #15: Yes
Case #16: No
Case #17: Yes
Case #18: No
Case #19: Yes
Case #20: Yes
Case #21: No
Case #22: No
Case #23: No
Case #24: No
Case #25: No
Case #26: No
Case #27: No
Case #28: No
Case #29: Yes
Case #30: Yes

【D题:水果忍者】

对于任意一个最优切割线,总可以通过平移或旋转得到一条经过某两点的切割线,而且这条切割线仍然是最优切割线。

#include<cstdio>
#include<cstring>

struct Point
{
    int x, y;
    Point() {}
    Point(int _x, int _y) : x(_x), y(_y) {}
    inline void readin() { scanf("%d %d", &x, &y); }
    inline Point operator+(const Point &cp) const { return Point(x + cp.x, y + cp.y); }
    inline Point operator-(const Point &cp) const { return Point(x - cp.x, y - cp.y); }
    inline int operator*(const Point &cp) const { return x * cp.y - y * cp.x; }
};

struct Line
{
    Point s, e;
    Line() {}
    Line(Point _s, Point _e) : s(_s), e(_e) {}
};

#define Segment Line

int isIntersected(Line L, Segment S)
{
    int a = (L.e - L.s) * (S.s - L.e);
    int b = (L.e - L.s) * (S.e - L.e);
    return (a * b <= 0);
}

const int maxN = 10 + 2;

int N, K[maxN];
Point P[maxN][maxN];
int nS, Select[maxN];

int gao()
{
    static Point H[maxN * maxN]; int nh = 0;
    for(int i = 0; i < nS; i++)
        for(int j = 0; j < K[ Select[i] ]; j++)
            H[nh ++] = P[ Select[i] ][ j ];

    for(int i = 0; i < nh; i++)
        for(int j = i + 1; j < nh; j++) {
            int yes = 0;
            for(int k = 0; k < nS; k++)
                for(int r = 0; r < K[ Select[k] ]; r++)
                    if( isIntersected(Line(H[i], H[j]),
                            Line(P[Select[k]][r], P[Select[k]][(r + 1) % K[ Select[k] ]])) )
                        { yes ++; break; }
            if( yes == nS )
                return 1;
        }

    return 0;
}

int main()
{
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
    int idx = 0, nt; scanf("%d", &nt);
    while( (nt --) > 0 ) {
        scanf("%d", &N);
        for(int i = 0; i < N; i++) {
            scanf("%d", K + i);
            for(int j = 0; j < K[i]; j++)
                P[i][j].readin();
        }
        int ans = 1, up = 0x1 << N;
        for(int i = 3; i < up; i++) {
            nS = 0;
            for(int j = 0; j < N; j++)
                if( i & (0x1 << j) )
                    Select[nS ++] = j;
            if( nS <= ans ) continue;
            if( gao() ) ans = nS;
        }
        printf("Case #%d: %d\n", ++ idx, ans);
    }
    return 0;
}

【E题:中位数】

树状数组,或线段树。

#include <vector>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <queue>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <string>
#include <cassert>
typedef long long i64d;
typedef unsigned long long i64u;
using namespace std;

template<class T> inline T cAbs(T x) { if( x < 0 ) return -x; return x; }
template<class T> inline T cMax(T a, T b) { return a > b ? a : b; }
template<class T> inline T cMin(T a, T b) { return a < b ? a : b; }

const int maxN = 250000 + 10;

const i64d Mod = 65536;

i64d A[maxN]; int N, K;

int C[65536 + 10];

int lowbit(int x)
{
	return x & (-x);
}

void update(int pos, int val)
{
	while( pos <= 65536 ) {
		C[pos] += val;
		pos += lowbit(pos);
	}
}

int query(int pos)
{
	int sum = 0;
	while( pos > 0 ) {
		sum += C[pos];
		pos -= lowbit(pos);
	}
	return sum;
}

int main()
{
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
	i64d seed, mul, add;
	while( scanf("%lld %lld %lld", &seed, &mul, &add) == 3 ) {
		scanf("%d %d", &N, &K);
		A[0] = seed;
		for(int i = 1; i < N; i++)
			A[i] = (A[i - 1] * mul + add) % Mod;

		if( K == 1 ) {
			i64d ans = 0LL;
			for(int i = 0; i < N; i++)
				ans += A[i];
			printf("%lld\n", ans);
			continue;
		}

		if( K == 2 ) {
			i64d ans = 0LL;
			for(int i = 1; i < N; i++)
				ans += min(A[i], A[i - 1]);
			printf("%lld\n", ans);
			continue;
		}

		// add 1
		for(int i = 0; i < N; i++)
			A[i] += 1LL;

		memset(C, 0, sizeof(C));
		int l, r, m, tot, tmp; i64d ans = 0LL;
		for(int i = 0; i < N; i++) {
			if( i < K - 1 )
				update((int)A[i], 1);
			else {
				update((int)A[i], 1);

				l = 1; r = 65536; tmp = 0;
				while( l <= r ) {
					m = (l + r) >> 1;
					tot = query(m);
					if( tot >= ((K + 1) / 2) ) {
						r = m - 1;
						tmp = m;
					}
					else
						l = m + 1;
				}

				ans += tmp;

				update((int)A[i - K + 1], -1);
			}
		}
		printf("%lld\n", ans - (N - K + 1LL));
	}
	return 0;
}

【F题:三角形的个数】

源自浙大月赛,考虑所有子矩形,对于每个子矩形,计算方案数,然后求和。对于每个子矩形,三角形的顶点在矩形边界的格点上,利用锐角性质,通过余弦定理得到格点间的不等式关系。


【G题:又见A+B】

模拟题,没有模出来,可以考虑再模一下。


【H题:K-数组】

排序后,统计计数即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>

using namespace std;

const int maxN = 50000 + 2;

int N, K;
struct node
{
    int val, idx;
    inline void in(int &_idx) { idx = _idx; scanf("%d", &val); }
    inline bool operator<(const node &s) const {
        if( val != s.val )
            return val < s.val;
        return idx < s.idx;
    }
};
node A[maxN];

int main()
{
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
    int idx = 0, nt; scanf("%d", &nt);
    while(  (nt --) > 0 ) {
        scanf("%d %d", &N, &K);
        for(int i = 0; i < N; i++) A[i].in(i);
        A[0].val %= K;
        for(int i = 1; i < N; i++) A[i].val = (A[i - 1].val + A[i].val) % K;

        sort(A, A + N); long long ans = 0;
        int preVal = 0, totVal = 1;
        for(int i = 0; i < N; i++) {
            if( preVal == A[i].val ) {
                ans += (long long)totVal;
                totVal ++;
            } else {
                preVal = A[i].val;
                totVal = 1;
            }
        }
        cout << "Case #" << ++idx << ": " << ans << endl;
    }
    return 0;
}

【I题:放苹果】

穷举法,这里放有几组输入数据的P值保留到小数点后面2位,似乎并不影响解答试题。

#include<cstdio>
#include<cstring>

int main()
{
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
    int idx = 0, nt;scanf("%d", &nt);
    while( (nt --) > 0 ) {
        int X, Y; double P; double ans = 0.0;
        scanf("%d %d %lf", &X, &Y, &P);
        for(int i = 0; i <= X; i ++)
            for(int j = 0; j <= Y; j++) {
                double cmp = 0.0;
                if( j ) cmp += P * j / (i + j);
                if( Y - j ) cmp += (1.0 - P) * (Y - j) / (X - i + Y - j);
                if( cmp > ans ) ans = cmp;
            }
        printf("Case #%d: %.2lf\n", ++idx, ans);
    }
    return 0;
}

测试数据:

输入

30
1 1 0.5
1 1 0.0
0 0 0
0 1 0
0 1 1
10 10 0.1
100 100 0.1
100 100 0.0
100 100 0.2
100 100 0.3
100 100 0.4
100 100 0.5
100 100 0.6
100 100 0.7
100 100 0.8
100 100 0.9
56 92 0.3
14 19 0.7
20 4 0.3
12 31 0.8
56 65 0.1
65 21 0.7
13 12 0.5
16 15 0.55
10 12 0.6
32 71 0.23
31 31 0.5
31 31 0.9
17 81 0.42
61 57 0.33

输出

Case #1: 0.50
Case #2: 1.00
Case #3: 0.00
Case #4: 1.00
Case #5: 1.00
Case #6: 0.95
Case #7: 0.95
Case #8: 1.00
Case #9: 0.90
Case #10: 0.85
Case #11: 0.80
Case #12: 0.75
Case #13: 0.80
Case #14: 0.85
Case #15: 0.90
Case #16: 0.95
Case #17: 0.89
Case #18: 0.87
Case #19: 0.74
Case #20: 0.94
Case #21: 0.95
Case #22: 0.77
Case #23: 0.73
Case #24: 0.76
Case #25: 0.81
Case #26: 0.93
Case #27: 0.75
Case #28: 0.95
Case #29: 0.93
Case #30: 0.83

Thank you for your reading!


P.S. 测试数据难免会有差错,敬请指正!个人不推荐短时间内希望得到测试数据,一定程度上,不能提高个人能力。

你可能感兴趣的:(2012年"新秀杯"程序设计比赛——现场决赛参考题解)