2016.1.19 ACM算法讨论群 群赛

本文解析了五道ACM竞赛题目,包括威佐夫博弈、数学处理、枚举算法、贪心策略及并查集应用,提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

套题链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=104302#overview

难度类型:比较基础,除了A需要知道较为偏门的知识,E需要使用并查集。

A

题解

类型:威佐夫博奕

理论上这个算是最难的,因为比较偏门,但是只要接触过的话套个模板上去即可。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>

#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
// head
double phi = (1+sqrt(5))/2.0;

int main()
{
    int n, m;
    while (scanf("%d%d", &n, &m) == 2) {
        int x = phi*abs(n-m);
        puts(min(n, m) == x ? "0" : "1");
    }
    return 0;
}

B

题解

类型:数学

相当于要去求 logbase(n!)+1 预处理出 ln(n!) 然后转换成 base 为底即可。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>

#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
// head
const int N = 1E6+5;

double a[N];
int main()
{
    for (int i = 1; i <= 1000000; i++) {
        a[i] = a[i-1]+log(i);
    }

    int t, n, m, cas = 1;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &m);
        printf("Case %d: %.0f\n", cas++, 1+floor(a[n]/log(m)));
    }
    return 0;
}

C

题解

类型:枚举

数据很宽松,直接立方暴力即可,当然有更快的做法,我想到最好的是常数较大的线性。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>

#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
// head
const int N = 105;

int a[N];
int main()
{
    int n, ans = 0;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", a+i);
    }

    for (int i = 0; i < n; i++) {
        for (int j = i; j < n; j++) {
            int temp = 0;
            for (int k = i; k <= j; k++) {
                temp ^= a[k];
            }
            ans = max(ans, temp);
        }
    }

    printf("%d\n", ans);
    return 0;
}

D

题解

类型:贪心

需要绕一定弯的贪心,首先一定是长度越长越好,长度相同高权位越大越好。于是可以先确定下来最终的位数,即以最小的数字先去取好,然后将代价和总花费进行偏移,就能以0为分界点去做了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>

#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
// head
int a[15];
int main()
{
    int n, len = 0, minv = 1e9;

    scanf("%d", &n);
    for (int i = 1; i <= 9; i++) {
        scanf("%d", a+i);
        len = max(len, n/a[i]);
        minv = min(minv, a[i]);
    }

    if (len == 0) {
        puts("-1");
        return 0;
    }

    for (int i = 1; i <= 9; i++) {
        a[i] -= minv;
    }
    n -= minv*len;
    for (int i = 0; i < len; i++) {
        for (int j = 9; j > 0; j--) {
            if (a[j] <= n) {
                n -= a[j];
                putchar('0'+j);
                break;
            }
        }
    }
    return 0;
}

E

题解

类型:并查集

维护连通性使用并查集,弄个数组维护有没有出现骑士。不断维护祖先的最大值,在合并时进行更新即可。根据维护的数据输出结果。比较好想到,代码还是有点长的。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>

#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
// head
const int N = 1005;
const int M = N*N;

int fa[M];
int v[M];
bool vis[N][N];

int find(int key) {
    return (key == fa[key]) ? key : (fa[key] = find(fa[key]));
}

void init(int n) {
    for (int i = 0; i < n; i++) {
        fa[i] = i;
    }
}

void joint(int a, int b) {
    a = find(a), b = find(b);
    if (a != b) {
        fa[a] = b;
        v[b] = max(v[b], v[a]);
    }
}

bool same(int u, int v) {
    return find(u) == find(v);
}

int t, n, q, x, y, val;

int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};

bool isok(PII &cur) {
    return cur.fi > 0 && cur.fi <= n && cur.se > 0 && cur.se <= n;
}

int convert(int x, int y) {
    return (x-1)*n+y-1;
}

char s[5];
int main()
{
    char ch;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &q);
        init(n*n);

        for (int i = 0; i < q; i++) {
            scanf("%s%d%d", s, &x, &y);

            if (s[0] == 'C') {
                scanf("%d", &val);
                for (int dir = 0; dir < 4; dir++) {
                    PII nxt = mp(x + dx[dir], y + dy[dir]);
                    if (isok(nxt) && vis[nxt.fi][nxt.se]) {
                        joint(convert(x, y), convert(nxt.fi, nxt.se));
                    }
                }
                int pos = find(convert(x, y));
                v[pos] = max(v[pos], val);
                vis[x][y] = true;
            } else {
                int pos = find(convert(x, y));
                printf("%d\n", vis[x][y] ? v[pos] : -1);
            }
        }

        memset(vis, 0, sizeof vis);
        memset(v, 0, sizeof v);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值