广东工业大学第12届ACM程序设计大赛部分题解

来源:互联网 发布:arm服务器 知乎 编辑:程序博客网 时间:2024/06/06 15:10

A

#include <cstdio>#include <cmath>#include <cstring>#include <sstream>#include <iostream>#include <algorithm>#include <queue>#include <stack>#include <string>#include <vector>#include <map>#include <set>#include <utility> using namespace std;#define LL long long#define pb push_back#define mk make_pair#define pill pair<int, int>#define mst(Arr, x) memset(Arr, x, sizeof(Arr))#define REP(i, x, n)    for(int i = x; i < n; ++i)const int qq = 1e5 + 10;const int INF = 1e9 + 10;int n, m; int main(){    int t;  scanf("%d", &t);    while(t--){        int a, b, c;        scanf("%d%d%d", &a, &b, &c);        int num = c / 4;        int x = num - b;        int y = num - a / 2;        printf("%d\n", num - x - y);    }    return 0;} /**************************************************************    Problem: 1224    User: Yokile    Language: C++    Result: Accepted    Time:0 ms    Memory:1696 kb****************************************************************/



B

参考官方题解:

令 d = abs(x1-x2)+abs(y1-y2)首先判断(n+1)/2 >= d,先手可不可以从一个点走到另一个点 :

如果不可以,则先手可以多得 n&1 分(因为劣势者可以选择逃离)

如果可以,考虑 d 的奇偶性:如果 d 为奇数(先手可以先踩到后手覆盖过的点):

如果 n 为奇数,先手可以多得 2 分,否则平。否则(d 为偶数)

:如果 n 为奇数,先手可以多得 1 分,否则后手可以多得 1 分。


#include <cstdio>#include <cmath>#include <cstring>using namespace std;#define LL long longint main(){int t;scanf("%d", &t);while(t--){LL n, x1, x2, y1, y2;scanf("%lld%lld%lld%lld%lld", &n, &x1, &y1, &x2, &y2);LL d = abs(x1 - x2) + abs(y1 - y2);LL ans = -1;if((n + 1) / 2 >= d){if(d % 2 == 0){ans = 1;}else{if(n & 1)ans = 2;}}else if(n & 1){ans = 1;}printf("%lld\n", ans);}return 0;}

这题还是不难的,- - 、果然还是萌新阿


C

这题也就是简单地递推, 然后乘法原理即可

#include <cstdio>#include <cmath>#include <cstring>#include <sstream>#include <iostream>#include <algorithm>#include <queue>#include <stack>#include <string>#include <vector>#include <map>#include <set>#include <utility> using namespace std;#define LL long long#define pb push_back#define mk make_pair#define pill pair<int, int>#define mst(Arr, x) memset(Arr, x, sizeof(Arr))#define REP(i, x, n)    for(int i = x; i < n; ++i)const int qq = 1e5 + 10;const int INF = 1e9 + 10;const int MOD = 10007;int n;LL dp[30]; int main(){    dp[0] = 0, dp[1] = 1, dp[2] = 2, dp[3] = 4;    for(int i = 4; i <= 20; ++i)        dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];    int t;  scanf("%d", &t);    while(t--){        scanf("%d", &n);        LL tot = 1;        REP(i, 1, n){            int x;  scanf("%d", &x);            tot = (tot * dp[x]) % MOD;        }        printf("%lld\n", tot);    }    return 0;} /**************************************************************    Problem: 1226    User: Yokile    Language: C++    Result: Accepted    Time:0 ms    Memory:1696 kb****************************************************************/


D

#include <cstdio>#include <cmath>#include <cstring>#include <sstream>#include <iostream>#include <algorithm>#include <queue>#include <stack>#include <string>#include <vector>#include <map>#include <set>#include <utility> using namespace std;#define LL long long#define pb push_back#define mk make_pair#define pill pair<int, int>#define mst(Arr, x) memset(Arr, x, sizeof(Arr))#define REP(i, x, n)    for(int i = x; i < n; ++i)const int qq = 1e5 + 10;const int INF = 1e9 + 10;int n, m; int main(){    int t;  scanf("%d", &t);    while(t--){        LL a, b, c; scanf("%lld%lld%lld", &a, &b, &c);        LL sum = a * b;        sum = sum + (a / 10 / 3) * c;        printf("%lld\n", sum);    }    return 0;} /**************************************************************    Problem: 1227    User: Yokile    Language: C++    Result: Accepted    Time:0 ms    Memory:0 kb****************************************************************/


E

这题貌似标程除了问题 题目还需要重判,但我觉得我的算法没啥问题

首先要尽可能的缩小瓶子数目,不断除2, 但是当瓶子数目为奇数时就会剩下一瓶,这时候这瓶水就要独立出来,放入一个集合中

最后这个集合进行操作, 首先要明确, 如果你有一瓶x升的水, 这个水一定是2^n, 不会是别的数了, 如果队列中不存在另外一个x,那么就必须补充x瓶水

因为每次都是对最小的进行操作,所以最后求出来肯定是最小的

#include <cstdio>#include <cmath>#include <cstring>#include <sstream>#include <iostream>#include <algorithm>#include <queue>#include <stack>#include <string>#include <vector>#include <map>#include <set>#include <utility>using namespace std;#define LL long long#define pb push_back#define mk make_pair#define pill pair<int, int>#define mst(Arr, x) memset(Arr, x, sizeof(Arr))#define REP(i, x, n)    for(int i = x; i < n; ++i)const int qq = 1e5 + 10;const int INF = 1e9 + 10;int n, m, k;int main(){    int t;  scanf("%d", &t);    while(t--){        priority_queue<int, vector<int>, greater<int> > Q;        scanf("%d%d", &n, &k);        int t = 1;        while(n){            if(n & 1)   Q.push(t);            n /= 2;            t <<= 1;        }        LL minx = 0;        while((int)Q.size() > k){            int x = Q.top();    Q.pop();            int y = Q.top();    Q.pop();            if(x == y){                Q.push(x + y);            }else{                minx += x;                Q.push(x + x);                Q.push(y);            }        }        printf("%lld\n", minx);    }    return 0;}


F

Tarjan离线求出最近公共祖先, 然后求这条路径上所有线段的长度, 然后排一次序, 然后每三个相邻的数判断一下能不能形成三角形

没给时间限制, 就暴力做了, 没想到还过了。。。。

昨天学长教我这题的正确解题姿势, 线段的长度都在1到1e9内, 我们可以这样想,假设三条线段a,b,c,令a<=b=<c, 如果满足a + b > c那么一定是个三角形,那么不满足的极限条件就是a + b = c, 换一种说法,就是在区间1到1e9内选择尽量多的数,使得选择出来的任意三个数都不能组成三角形, 这样推出来的结论就是这些选择出来的数满足菲波那契数列, 然后就可以根据路径的长度进行剪枝了,最终的复杂度还是O(m + q)。学长说好像是2016年大连区域赛的一道题也是这样剪的

#include <cstdio>#include <cmath>#include <cstring>#include <sstream>#include <iostream>#include <algorithm>#include <queue>#include <stack>#include <string>#include <vector>#include <map>#include <set>#include <utility> using namespace std;#define LL long long#define pb push_back#define mk make_pair#define pill pair<int, int>#define mst(Arr, x) memset(Arr, x, sizeof(Arr))#define REP(i, x, n)    for(int i = x; i < n; ++i)const int qq = 1e5 + 10;const int INF = 1e9 + 10;int n, m, top;int fa[qq], pre[qq], head[qq], plen[qq], anc[qq];int num[qq];int l[qq], r[qq];bool vis[qq];struct Edge{    int v, next, w;}edge[qq * 2];vector<int> q[qq], f[qq];void Add(int u, int v, int w){    edge[top].v = v;    edge[top].w = w;    edge[top].next = head[u];    head[u] = top++;}void Init(){    mst(head, -1);    mst(vis, false);    mst(plen, 0);    mst(anc, 0);    top = 0;    for(int i = 0; i <= n; ++i)        q[i].clear(), f[i].clear(); }int Find(int x){    return fa[x] == -1 ? x : fa[x] = Find(fa[x]);}void Union(int x, int y){    int b = Find(y);    if(x != b)  fa[b] = x;}void Tarjan(int u, int p, int w){    fa[u] = pre[u] = -1;    for(int i = head[u]; i != -1; i = edge[i].next){        int v = edge[i].v;        if(v == p || vis[v])    continue;        Tarjan(v, u, edge[i].w);        Union(u, v);    }    vis[u] = true;    pre[u] = p;    plen[u] = w;    for(int i = 0; i < (int)q[u].size(); ++i)if(vis[q[u][i]]){        anc[f[u][i]] = Find(q[u][i]);    }}bool check(int c, int b, int a){    if(a + b > c && a + c > b && b + c > a)    return true;    return false;} int main(){    int t;  scanf("%d", &t);    while(t--){        Init();        scanf("%d", &n);        REP(i, 1, n){            int a, b, c;            scanf("%d%d%d", &a, &b, &c);            Add(a, b, c);            Add(b, a, c);        }        int m;  scanf("%d", &m);        REP(i, 0, m){            int a, b;scanf("%d%d", &a, &b);            l[i] = a, r[i] = b;            q[a].pb(b), f[a].pb(i);            q[b].pb(a), f[b].pb(i);        }        Tarjan(1, -1, 0);    /*for(int i = 0; i < m; ++i){            printf("%d\n", anc[i]);        }*/        REP(i, 0, m){            int cnt = 0;            int u = l[i];            int v = anc[i];            while(u != v){                num[cnt++] = plen[u];                u = pre[u];            }            u = r[i];            while(u != v){                num[cnt++] = plen[u];                u = pre[u];            }            sort(num, num + cnt);            bool flag = false;            for(int j = 2; j < cnt; ++j){                if(check(num[j], num[j - 1], num[j - 2])){                    flag = true;                    break;                }            }            if(flag)    puts("Yes");            else    puts("No");        }    }    return 0;} /**************************************************************    Problem: 1229    User: Yokile    Language: C++    Result: Accepted    Time:104 ms    Memory:11964 kb****************************************************************/


H

这题有个很显然的结论,你如果能凑出区间[0, x],那么对于一个数p,如果x + 1 >= p, 那么你就能凑出区间[0,x + p]的所有数

这题有个加强版的 传送门

#include <cstdio>#include <cmath>#include <cstring>#include <sstream>#include <iostream>#include <algorithm>#include <queue>#include <stack>#include <string>#include <vector>#include <map>#include <set>#include <utility> using namespace std;#define LL long long#define pb push_back#define mk make_pair#define pill pair<int, int>#define mst(Arr, x) memset(Arr, x, sizeof(Arr))#define REP(i, x, n)    for(int i = x; i < n; ++i)const int qq = 1e5 + 10;const int INF = 1e9 + 10;int n, m;LL num[qq]; int main(){    int t;  scanf("%d", &t);    while(t--){        scanf("%d", &n);        REP(i, 0, n){            scanf("%lld", num + i);        }        LL money = 0;        sort(num, num + n);        REP(i, 0, n){            if(num[i] <= money + 1){                money += num[i];            }else{                break;            }        }        printf("%lld\n", money);    }    return 0;} /**************************************************************    Problem: 1231    User: Yokile    Language: C++    Result: Accepted    Time:0 ms    Memory:0 kb****************************************************************/




0 0
原创粉丝点击