福州大学第十二届程序设计竞赛题解

A:这题利用单调栈,先预处理出每个位置向下的最远位置,那么每一行单独考虑,每行就相当于一些段的子矩阵个数,利用单调栈维护,每次出栈的时候把大于当前要入栈(高度0的不入栈了)的段的部分计算出来,累加一下答案即可

B:这题可以枚举,因为一个10^15开3方之后是10^5枚举起来是没有问题的,然后枚举一个数字i,等于要计算在max(a, i * i * i)到min(i * i * i, b)区间,有多少个x满足i * i * x在区间内,两边除下减下就能计算出答案了

C:并查集,注意每次合并的时候都要让城市作为根,最后对于人和服务找根,如果根的范围是城市,就表明信息是是全的

D:水题,用字符串存浮点数去计算,gcd约分下即可

E:这题。。显然没有很奇葩的数据,于是只要把不能互相在一个集合的连边,然后利用二分图染色判定,如果矛盾就无解,如果不矛盾,每次就取一个子集内黑白点多的一边累加,得到的答案就是最终答案

F:树形DP,dp[u][0]和dp[u][1]分别表示不回,回树根的最小代价,那么对于一个子树,回树根的代价是固定的,就是他的子树代价+边权,那么不回的代价就是任意选一个子树不回,这样的话,只要在找子节点的过程中,记录这个答案的最大值,那么用dp[u][1]减去这个值就能得到dp[u][0]的最小值

G:大白书上有这题,先对火做一个BFS计算出每个点的蔓延时间,然后利用这个时间,在对人做一个BFS,注意这题有个坑点,就是如果人走到出口就直接出去了,因为岩浆是后蔓延到的

H:贪心,对于y操作,最好的肯定是把后面的1放到前面的0的位置,那么就是要找一个临界值,后面放X个1,其余都使用x操作一步步挪到前面,这个直接枚举,然后维护一些前缀和七七八八的东西。写起来还是要注意细节,具体见代码

代码:

A:

#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;

typedef long long ll;
const int N = 2005;
int n, m;
char str[N];
int g[N][N];
stack<pair<int, int> > S;

ll get(int s, int k) {
    return (ll)(2 * s - (k - 1)) * k / 2;
}

int main() {
    while (~scanf("%d%d", &n, &m)) {
        for (int i = 0; i < n; i++) {
            scanf("%s", str);
            for (int j = 0; j < m; j++) {
                if (str[j] == 'b') g[i][j] = 0;
                else g[i][j] = 1;
            }
        }
        for (int i = 0; i < m; i++) {
            int pre = n;
            for (int j = n - 1; j >= 0; j--) {
                if (g[j][i] == 0) pre = j;
                g[j][i] = pre;
            }
        }
        for (int i = 0; i < n; i++) g[i][m] = i;
        ll ans = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= m; j++) {
                int h = g[i][j] - i, v = j, pre = j;
                while (!S.empty() && S.top().first > h) {
                    v = S.top().second;
                    ans += get(j - v, pre - v) * (S.top().first - h);
                    pre = v;
                    S.pop();
                }
                if (h) S.push(make_pair(h, v));
            }
        }
        printf("%I64d\n", ans);
    }
    return 0;
}

B:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long ll;

ll a, b;
ll ans;

int main() {
    while (~scanf("%I64d%I64d", &a, &b)) {
        ans = 0;
        for (ll i = 1; i * i * i <= b; i++) {
            ll sb = max(a, i * i * i);
            ans += b / (i * i) - (sb - 1) / (i * i);
        }
        printf("%I64d\n", ans);
    }
    return 0;
}

C:

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

const int MAXN = 400005;
const int N = 100000;
const int M = 100000;
int n, m, q;

int parent[MAXN];

int find(int x) {
    if (x == parent[x])return x;
    return parent[x] = find(parent[x]);
}

void uni(int a, int b) {
    int pa = find(a);
    int pb = find(b);
    if (pb < pa) swap(pb, pa);
    if (pa != pb) parent[pa] = pb;
}

int main() {
    while (~scanf("%d%d%d", &n, &m, &q)) {
        int a, b, c;
        for (int i = 0; i < MAXN; i++)
            parent[i] = i;
        for (int i = 1; i <= n; i++) {
            scanf("%d%d", &a, &b);
            a--; b--;
            if (b != -1) {
                uni(a, b + N + M);
            }
        }
        for (int i = 1; i <= m; i++) {
            scanf("%d%d%d", &a, &b, &c);
            a--; b--; c--;
            uni(a + N, b);
            if (c != -1) {
                uni(a + N, c + N + M);
                uni(b, c + N + M);
            }
        }
        int tp,id;
        while (q--) {
            scanf("%d%d", &tp, &id);
            id--;
            if (tp == 1) id += N;
            int x = find(id);
            if (x >= N + M) printf("%d\n", x - (N + M) + 1);
            else printf("0\n");
        }
    }
    return 0;
}

D:

#include <cstdio>
#include <cstring>

int t;
char n[105];

typedef long long ll;

ll gcd(ll a, ll b) {
    if (!b) return a;
    return gcd(b, a % b);
}

int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%s", &n);
        int len = strlen(n);
        ll sb = 0, fuck = 1;
        for (int i = 0; i < len; i++) {
            if (n[i] == '.') {
                for (int j = i + 1; j < len; j++) {
                    sb = sb * 10 + n[j] - '0';
                    fuck *= 10;
                }
                break;
            }
            sb = sb * 10 + n[i] - '0';
        }

        ll d = gcd(sb, fuck);
        printf("%I64d/%I64d\n", sb / d, fuck / d);
    }
    return 0;
}

E:

#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;

typedef long long ll;
const int N = 50005;
int n, col[N];
vector<int> g[N];

struct Point {
    int x, y;
    void read() {
        scanf("%d%d", &x, &y);
    }
} p[N];

bool cmpx(Point a, Point b) {
    return a.x < b.x;
}

int w[2], ans;

bool dfs(int u) {
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (col[u] == col[v]) return false;
        if (col[v] == -1) {
            col[v] = !col[u];
            w[col[v]]++;
            dfs(v);
        }
    }
    return true;
}

ll dis(Point a, Point b) {
    ll dx = a.x - b.x;
    ll dy = a.y - b.y;
    return dx * dx + dy * dy;
}

int main() {
    while (~scanf("%d", &n)) {
        for (int i = 0; i < n; i++) {
            p[i].read();
            g[i].clear();
            col[i] = -1;
        }
        sort(p, p + n, cmpx);
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; p[j].x - p[i].x <= 5; j++) {
                if (dis(p[j], p[i]) <= 25LL) {
                    g[i].push_back(j);
                    g[j].push_back(i);
                }
            }
        }
        int flag = 0;
        ans = 0;
        for (int i = 0; i < n; i++) {
            if (col[i] == -1) {
                col[i] = 0;
                w[0] = 1; w[1] = 0;
                if (!dfs(i)) {
                    flag = 1;
                    break;
                }
                ans += max(w[0], w[1]);
            }
        }
        if (flag) printf("-1\n");
        else printf("%d\n", ans);
    }
    return 0;
}

F:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

const int N = 100005;
int n;
const int INF = 0x3f3f3f3f;
int cost[N], vis[N], dp[N][2];
vector<int> g[N];

void dfs(int u) {
    dp[u][0] = dp[u][1] = 0;
    if (g[u].size() == 0)
        return;
    int Min = -INF, Minv;
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        dfs(v);
        if (Min < dp[v][1] - dp[v][0] + cost[v]) {
            Min = dp[v][1] - dp[v][0] + cost[v];
            Minv = v;
        }
        dp[u][1] += dp[v][1] + cost[v];
    }
    dp[u][0] = dp[u][1] - dp[Minv][1] - cost[Minv] + dp[Minv][0];
}

int main() {
    while (~scanf("%d", &n)) {
        int u, v, w;
        for (int i = 1; i <= n; i++) {
            vis[i] = 0;
            g[i].clear();
        }
        for (int i = 0; i < n - 1; i++) {
            scanf("%d%d%d", &u, &v, &w);
            g[u].push_back(v);
            cost[v] = w;
        }
        dfs(1);
        printf("%d\n", dp[1][0]);
    }
    return 0;
}

G:

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

const int N = 1005;
const int INF = 0x3f3f3f3f;
char g[N][N];
int t, n, m;

struct Point {
    int x, y;
    Point() {}
    Point(int x, int y){
        this->x = x;
        this->y = y;
    }
} s, e;

const int d[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};

int bid[N][N], vis[N][N];

int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &m);
        queue<Point> Q;
        for (int i = 0; i < n; i++) {
            scanf("%s", g[i]);
            for (int j = 0; j < m; j++) {
                bid[i][j] = INF;
                vis[i][j] = INF;
                if (g[i][j] == 'S') {
                    s.x = i;
                    s.y = j;
                }
                if (g[i][j] == '!') {
                    Q.push(Point(i, j));
                    bid[i][j] = 0;
                }
                if (g[i][j] == 'E') {
                    e.x = i;
                    e.y = j;
                }
            }
        }
        while (!Q.empty()) {
            Point u = Q.front(); Q.pop();
            for (int i = 0; i < 4; i++) {
                Point v;
                v.x = u.x + d[i][0];
                v.y = u.y + d[i][1];
                if (v.x < 0 || v.x >= n || v.y < 0 || v.y >= m || g[v.x][v.y] == '#') continue;
                if (bid[v.x][v.y] > bid[u.x][u.y] + 1) {
                    bid[v.x][v.y] = bid[u.x][u.y] + 1;
                    Q.push(v);
                }
            }
        }
        Q.push(s);
        vis[s.x][s.y] = 0;
        int flag = 0;
        while (!Q.empty()) {
            Point u = Q.front(); Q.pop();
            for (int i = 0; i < 4; i++) {
                Point v;
                v.x = u.x + d[i][0];
                v.y = u.y + d[i][1];
                if (v.x < 0 || v.x >= n || v.y < 0 || v.y >= m || g[v.x][v.y] == '#') continue;
                if (v.x == e.x && v.y == e.y && bid[v.x][v.y] >= vis[u.x][u.y] + 1) {
                    flag = 1;
                    break;
                }
                if (bid[v.x][v.y] <= vis[u.x][u.y] + 1) continue;
                if (vis[v.x][v.y] > vis[u.x][u.y] + 1) {
                    vis[v.x][v.y] = vis[u.x][u.y] + 1;
                    Q.push(v);
                }
            }
        }
        printf("%s\n", flag ? "Yes" : "No");
    }
    return 0;
}

H:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 100005;

typedef long long ll;
int t, n;
char str[N];
ll x, y;
int one[N], zero[N], on, zn;
ll sum[N], bit[N];

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

void add(int x, int v) {
    while (x <= n) {
        bit[x] += v;
        x += lowbit(x);
    }
}

ll get(int x) {
    ll ans = 0;
    while (x) {
        ans += bit[x];
        x -= lowbit(x);
    }
    return ans;
}

int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%I64d%I64d", &x, &y);
        scanf("%s", str + 1);
        n = strlen(str + 1);
        memset(bit, 0, sizeof(bit));
        on = zn = 0;
        ll tot = 0;
        ll sb = 0;
        for (int i = 1; i <= n; i++) {
            sum[i] = sum[i - 1];
            if (str[i] == '1') {
                tot += sb;
                one[on++] = i;
                sum[i] += 1;
            } else {
                sb++;
                add(i, 1);
            }
        }
        for (int i = n; i >= 1; i--) if (str[i] == '0') zero[zn++] = i;
        ll ans = 0;
        while (on && zn && one[on - 1] > zero[zn - 1]) {
            if (x * tot < y + x * (tot - get(one[on - 1]) - (sum[one[on - 1] - 1] - sum[zero[zn - 1]]))) {
                ans += x * tot;
                break;
            } else {
                tot -= get(one[on - 1]) + (sum[one[on - 1] - 1] - sum[zero[zn - 1]]);
                add(zero[zn - 1], -1);
                zn--; on--;
                ans += y;
            }
        }
        printf("%I64d\n", ans);
    }
    return 0;
}
时间: 2024-08-04 23:11:04

福州大学第十二届程序设计竞赛题解的相关文章

福州大学第十二届程序设计竞赛 (部分题解)

比赛链接:http://acm.fzu.edu.cn/contest/list.php?cid=144 Problem B 完美的数字 Time Limit: 1000 mSec    Memory Limit : 32768 KB Problem Description Bob是个很喜欢数字的孩子,现在他正在研究一个与数字相关的题目,我们知道一个数字的完美度是 把这个数字分解成三个整数相乘A*A*B(0<A<=B)的方法数,例如数字80可以分解成1*1*80,2*2*20 ,4*4*5,所以

福州大学第十二届程序设计竞赛 B.完美的数字

Problem B 完美的数字 Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description Bob是个很喜欢数字的孩子,现在他正在研究一个与数字相关的题目,我们知道一个数字的完美度是 把这个数字分解成三个整数相乘A*A*B(0<A<=B)的方法数,例如数字80可以分解成1*1*80,2*2*20 ,4*4*5,所以80的完美度是3:数字5只有一种分解方法1*1*5,所以完美度是1,假设数字x的完美度为d(x),现在

福州大学第十届程序设计竞赛 -- 部分题解

题目传送:福州大学第十届程序设计竞赛 Problem A 神庙逃亡 水题 AC代码: #include<cstdio> #include<cmath> #include<iostream> using namespace std; int s, h, vx, vy; int main() { int w; cin >> w; while(w--){ cin >> s >> h >> vx >> vy; long

北京师范大学第十二届程序设计竞赛

感觉像是个人赛.只是要是个人赛的话他们真的是太牛了... 全然被虐爆了有没有啊. 整体来说题目不是非常难,以下就粘一下代码吧. 队友看的A,看完就发现了水题本质.可是敲的不是非常顺利. ..是由于太久没做比赛么.. #include<algorithm> #include<iostream> #include<cstring> #include<vector> #include<cstdio> #include<cmath> #inc

FZU-2231 平行四边形数 From 福州大学第十三届程序设计竞赛

FZU-Problem 2231 平行四边形数 Accept: 66 Submit: 210 Time Limit: 2000 mSec Memory Limit : 32768 KB Problem Description 在一个平面内给定n个点,任意三个点不在同一条直线上,用这些点可以构成多少个平行四边形?一个点可以同时属于多个平行四边形. Input 多组数据(<=10),处理到EOF. 每组数据第一行一个整数n(4<=n<=500).接下来n行每行两个整数xi,yi(0<=

《ACM国际大学生程序设计竞赛题解Ⅰ》——基础编程题

这个专栏开始介绍一些<ACM国际大学生程序设计竞赛题解>上的竞赛题目,读者可以配合zju的在线测评系统提交代码(今天zoj貌似崩了). 其实看书名也能看出来这本书的思路,就是一本题解书,简单暴力的通过题目的堆叠来提升解决编程问题的能力. 那么下面开始探索吧. zoj1037: BackgroundFor years, computer scientists have been trying to find efficient solutions to different computing p

电信学院第一届新生程序设计竞赛题解及std

首先非常感谢各位同学的参加,还有出题验题同学的辛勤付出 昨天想偷懒就是不想再把我C++11的想法改没了,大家看不懂的可以百度一下哦,懒得再写gcc了,毕竟代码是通的 题目类型一览 A Kannyi的数字密码 (模拟&&复杂的循环||手算)B Kannyi爱干净(注意变量初始化||set)C Kannyi的正方体和圆柱体(输入输出签到,PI已提示)D kannyi的独木桥(max和min)E Kannyi的简单检查 (循环签到 注意'-')F Kannyi的倒计时(a+b签到)G kanny

西南科技大学第十届ACM程序设计竞赛题解

A.德州扑克 B. 我恨11(1089) 问题描述 11是一个孤独的数字,小明十分讨厌这个数字,因此如果哪个数字中出现了11或者该数字是11的倍数,他同样讨厌这个数字.现在问题来了,在闭区间[L,R]之间有多少个小明讨厌的数字. 输入 多组测试数据,每组两个整数L,R(1<=L<=R<=100000) 输出 小明讨厌的数的个数. 样例输入 1 11 11 111 样例输出 1 11 签到题.直接暴力即可 #include <stdio.h> int find(int x) {

2016年“计蒜客”杯华中师范大学第十四届程序设计竞赛题解

A. 寻找字符串 对于一个字符串 s,定义一个函数 S(x),表示 s 中有多少个子串 x.现在给定 S(a),S(b),S(ab),S(ba)的值,求满足这 4 个值的字符串 s,如果有多个满足条件的字符串,输出字典序最小的. s 中仅可能含有字符 a 和 b. 任何一个串的 S(ab) 与 S(ba) 的相差都不会超过1.可以分 S(ab)-S(ba) 为 0 -1 1 三种情况讨论.先构造出相应的 ab 相邻的串,再考虑按照字典序最小出要求将剩余的字母插入串中即可. 应该注意,这道问题有很