2013年腾讯编程马拉松初赛第0场(3月20日)解题参考

HDU4500:小Q系列故事——屌丝的逆袭


参考思路:模拟。

参考程序:

#include<cstdio>
#include<cstring>

const int maxN = 20 + 2;

int N, M;
int maze[maxN][maxN];

int dir[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
int ok(int x, int y) { return x >= 0 && y >= 0 && x < N && y < M; }
int cAbs(int x) { return x > 0 ? x : (-x); }

int main()
{
    while( scanf("%d %d", &N, &M) == 2 ) {
        if( N == 0 && M == 0 ) break;
        for(int i = 0; i < N; i ++)
            for(int j = 0; j < M; j ++)
                scanf("%d", maze[i] + j);
        int res = -1000000007, row = 0, col = 0;
        for(int i = 0; i < N; i ++) {
            for(int j = 0; j < M; j ++) {
                //if( maze[i][j] > 0 ) continue;
                int val = 0;
                for(int k = 0; k < 4; k ++) {
                    int u = i + dir[k][0];
                    int v = j + dir[k][1];
                    if( ok(u, v) ) {
                        if( maze[u][v] * maze[i][j] < 0 )
                            val += cAbs(maze[u][v]);
                        else 
                            if( maze[u][v] * maze[i][j] > 0 )
                                val -= cAbs(maze[u][v]);
                    }
                }
                if( val > res ) {
                    res = val;
                    row = i; col = j;
                }
            }
        }
        printf("%d %d %d\n", row + 1, col + 1, res);
    }
    return 0;
}

HDU4501:小明系列故事——买年货


参考思路:用最赤裸裸的DP可以过。

参考程序:

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxN = 100 + 2;
const int maxK = 5 + 2;

int dp[maxN][maxN][maxN][maxK];
int N, V1, V2, K;
int a[maxN], b[maxN], v[maxN];

int main()
{
    while( scanf("%d %d %d %d", &N, &V1, &V2, &K) == 4 ) {
        for(int i = 1; i <= N; i ++)
            scanf("%d %d %d", a + i, b + i, v + i);
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= N; i ++) {
            for(int j = 0; j <= V1; j ++) {
                for(int k = 0; k <= V2; k ++) {
                    for(int r = 0; r <= K; r ++) {
                        dp[i][j][k][r] = dp[i - 1][j][k][r];
                        if( j >= a[i] )
                            dp[i][j][k][r] = max(dp[i][j][k][r], v[i] + dp[i - 1][j - a[i]][k][r]);
                        if( k >= b[i] )
                            dp[i][j][k][r] = max(dp[i][j][k][r], v[i] + dp[i - 1][j][k - b[i]][r]);
                        if( r >= 1 )
                            dp[i][j][k][r] = max(dp[i][j][k][r], v[i] + dp[i - 1][j][k][r - 1]);
                    }
                }
            }
        }
        printf("%d\n", dp[N][V1][V2][K]);
    }
    return 0;
}

HDU4502:吉哥系列故事——临时工计划


参考思路:DP[ cur_time ] = max { DP[ cur_time - 1 ], DP[ pre_time ] + C[ someone_from_s_to_e ] }

参考程序:

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxN = 100 + 2;

int M;

struct node 
{
    int s, e, c;
    inline bool operator<(const node &cp) const { 
        if( e != cp.e ) return e < cp.e;
        return s < cp.s;
    }
    inline void in() { scanf("%d %d %d", &s, &e, &c); }
};
node A[maxN * 10]; int nA;

int dp[maxN];

int main()
{
    int nt; scanf("%d", &nt);
    while( (nt --) > 0 ) {
        scanf("%d %d", &M, &nA);
        for(int i = 0; i < nA; i ++) A[i].in();
        sort(A, A + nA); memset(dp, 0, sizeof(dp));
        int pd = 0, res = 0;
        for(int ti = 1; ti <= M; ti ++) {
            int cnt = 0;
            while( pd < nA && A[pd].e <= ti ) {
                cnt = max(cnt, dp[A[pd].s - 1] + A[pd].c);
                pd ++;
            }
            dp[ti] = max(cnt, dp[ti - 1]); res = max(res, dp[ti]);
        }
        printf("%d\n", res);
    }
    return 0;
}

HDU4503:湫湫系列故事——植树节



参考思路:考虑不合法的状态描述:只有两个小朋友是朋友。对于当前小朋友A,假设他有NA个朋友,那么如果A在这3个小朋友当中,那么不合法的状态有:NA * (total - NA - 1)个,其中,total表示总的小朋友个数。对于每一个小朋友都这么计算,得到“总的不合法状态数目”,注意,这里的“总的不合法状态数目”重复1次,所以,需要再除以2。原因在于:假设A和B是好朋友,而C与A、C与B都不是好朋友,那么在计算A和B时,状态<A, B, C>会被计算2次。

参考程序:

#include<cstdio>
#include<cstring>

const int maxN = 1000 + 2;

int d[maxN]; int N;

int main()
{
    int nt; scanf("%d", &nt);
    while( (nt --) > 0 ) {
        scanf("%d", &N);
        for(int i = 0; i < N; i ++) scanf("%d", d + i);
        int total = N * (N - 1) * (N - 2) / 6;
        int sub = 0;
        for(int i = 0; i < N; i ++) sub += d[i] * (N - 1 - d[i]);
        sub >>= 1; //printf("%d %d\n", total, sub);
        printf("%.3lf\n", (total - sub + 0.0) / total);
    }
    return 0;
}

HDU4504:威威猫系列故事——篮球梦



参考思路:

建立最终需要满足的不等式:

A_score = A + Sa(1) + Sa(2) + ... + Sa(times_A) > B_Score = B + Sb(1) + Sb(2) + ... + Sb(times_B)

表达的含义是:最终A的得分比B高,其中,Sa(i)表示A的某一场进攻得分,Sb(i)同理;times_A、times_B分别表示A和B可进攻的总次数。

根据题意,化简可得:

Sa(1) + Sa(2) + ... + Sa(times_A) > B + times_B - A

且有:times_B = (t / 15) / 2 和 times_A = (t / 15) - times_B。考虑到A最多进攻20次,枚举计数即可。

参考程序:

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int A, B, t, na, nb;

unsigned int dp[20 + 2][60 + 2];

void init()
{
    memset(dp, 0, sizeof(dp));
    dp[0][0] = 1;
    for(int i = 1; i <= 20; i ++) {
        for(int j = 0; j <= 60; j ++) {
            if( j > 3 * i ) break;
            if( j >= 1 ) dp[i][j] += dp[i - 1][j - 1];
            if( j >= 2 ) dp[i][j] += dp[i - 1][j - 2];
            if( j >= 3 ) dp[i][j] += dp[i - 1][j - 3];
        }
    }
}

int main()
{
    init();
    while( scanf("%d %d %d", &A, &B, &t) == 3 ) {
        int na = (t / 15 + 1) / 2;
        int nb = (t / 15) - na;
        // A + x1 + x2 + ... xna > B + nb
        // x1 + x2 + ... + xna > B + nb - A
        int left = B + nb - A;
        if( left > 3 * na ) printf("0\n");
        else {
            unsigned int res = 0;
            for(int i = max(left + 1, 0); i <= (3 * na); i ++)
                res += dp[na][i];
            printf("%u\n", res);
        }
    }
    return 0;
}


OpenSpirit @ SWJTU

你可能感兴趣的:(2013年腾讯编程马拉松初赛第0场(3月20日)解题参考)