2016年中国大学生程序设计竞赛(杭州)-重现赛

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chenzhenyu123456/article/details/52965642

感觉今天状态很差,06没考虑负数,最后一题脑残写反判定? 真的要退役了。
A
贪心模拟,不够就一直合并,多的话就一直分解。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
typedef pair<int, int> pii;
LL a[MAXN];
int main()
{
    int t, kcase = 1; scanf("%d", &t);
    while(t--) {
        int n, m; scanf("%d%d", &n, &m);
        LL sum = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            sum += a[i];
        }
        if(sum % m) {
            printf("Case #%d: -1\n", kcase++);
            continue;
        }
        LL ans = 0;
        LL aver = sum / m;
        int i = 1;
        for(int j = 1; j <= m && i <= n; i++) {
            while(i <= n && a[i] < aver) {
                a[i + 1] += a[i];
                i++; ans++;
            }
            while(a[i] > aver) {
                a[i] -= aver; ans++; j++;
            }
            if(a[i] == aver) {
                j++;
            }
            else {
                a[i + 1] += a[i]; ans++;
            }
        }
        printf("Case #%d: %lld\n", kcase++, ans);
    }
    return 0;
}

B
考虑每个SCC的入度,然后统计贡献。注意特判1的情况的。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#include <vector>
#include <stack>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXN = 1e3 + 10;
const int MOD = 1e9 + 7;
const int INF = 1e9 + 7;
typedef pair<int, int> pii;
vector<int> G[MAXN];
vector<int> scc[MAXN];
int x[MAXN], y[MAXN], r[MAXN], c[MAXN];
int low[MAXN], dfn[MAXN];
int dfs_clock;
bool Instack[MAXN];
int scc_cnt;
int sccno[MAXN];
stack<int> S;
void tarjan(int u, int fa) {
    int v;
    low[u] = dfn[u] = ++dfs_clock;
    Instack[u] = true; S.push(u);
    for(int i = 0; i < G[u].size(); i++) {
        v = G[u][i];
        if(!dfn[v]) {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        else if(Instack[v]) {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(low[u] == dfn[u]) {
        scc_cnt++;
        scc[scc_cnt].clear();
        for(;;) {
            v = S.top(); S.pop();
            sccno[v] = scc_cnt;
            scc[scc_cnt].push_back(v);
            Instack[v] = false;
            if(v == u) break;
        }
    }
}
void find_cut(int l, int r) {
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
    memset(sccno, 0, sizeof(sccno));
    memset(Instack, false, sizeof(Instack));
    dfs_clock = scc_cnt = 0;
    for(int i = l; i <= r; i++) {
        if(!dfn[i]) {
            tarjan(i, -1);
        }
    }
}
int in[MAXN];
int main()
{
    int t, kcase = 1; scanf("%d", &t);
    while(t--) {
        int n; scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%d%d%d%d", &x[i], &y[i], &r[i], &c[i]);
        }
        for(int i = 1; i <= n; i++) {
            G[i].clear();
            for(int j = 1; j <= n; j++) {
                if(i == j) continue;
                if(1LL * (x[j] - x[i]) * (x[j] - x[i]) + 1LL * (y[j] - y[i]) * (y[j] - y[i]) <= 1LL * r[i] * r[i]) {
                    G[i].push_back(j);
                }
            }
        }
        find_cut(1, n);
        for(int i = 1; i <= scc_cnt; i++) in[i] = 0;
        for(int i = 1; i <= n; i++) {
            for(int j = 0; j < G[i].size(); j++) {
                int u = sccno[i];
                int v = sccno[G[i][j]];
                if(u != v) {
                    in[v]++;
                }
            }
        }
        LL ans = 0;
        if(scc_cnt == 1) {
            sort(c + 1, c + n + 1);
            ans = c[1];
        }
        else {
            for(int i = 1; i <= scc_cnt; i++) {
                if(in[i]) continue;
                int Min = INF;
                for(int j = 0; j < scc[i].size(); j++) {
                    Min = min(Min, c[scc[i][j]]);
                }
                ans += Min;
            }
        }
        printf("Case #%d: %lld\n", kcase++, ans);
    }
    return 0;
}

C
贪心,从后向前模拟。
但是直接用double精度可能会不够,最好的方法就是使用分数的形式。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <stack>
#include <cmath>
#include <iostream>
using namespace std;
typedef unsigned long long LL;
const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
const int INF = 1e9 + 7;
typedef pair<int, int> pii;
LL a[MAXN];
LL gcd(LL a, LL b) {
    return b == 0 ? a : gcd(b, a % b);
}
int main()
{
    int t, kcase = 1; scanf("%d", &t);
    while(t--) {
        int n; scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%llu", &a[i]);
        }
        LL ans = 1; a[0] = 0;
        LL v1 = a[n] - a[n - 1];
        LL v2 = 1;
        for(int i = n - 1; i >= 1; i--) {
            LL d = a[i] - a[i - 1];
            if(v1 >= d * v2) {
                v1 = d; v2 = 1; ans++;
            }
            else {
                if((d * v2) % v1 == 0) {
                    ans += d * v2 / v1;
                }
                else {
                    LL num = d * v2 / v1 + 1;
                    v1 = d; v2 = num;
                    LL GCD = gcd(v1, v2);
                    v1 /= GCD; v2 /= GCD;
                    ans += num;
                }
            }
        }
        printf("Case #%d: %llu\n", kcase++, ans);
    }
    return 0;
}

D
首先打个表,发现 y < 10 10
高效的枚举 y ,可以将 y 分两半,类似科学计数法记 y = x 10 5 + y ,里面 x y 均小于 10 5 。预处理前一半,然后统计个数,再枚举后一半,统计贡献。
注意 y > 0 。。。。
代码写的太弱智

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXN = 1e4 + 10;
const int MOD = 1e9 + 7;
typedef pair<int, int> pii;
LL f[10][10];
LL W(int bit) {
    LL ans = 0;
    for(int i = 1; i <= bit; i++) {
        ans = ans * 10 + 9;
    }
    return ans;
}
LL sum[100000 + 10][10];
LL rec[100000 + 10], val[100000 + 10];
int num[100000 + 10];
int main()
{
    for(int i = 0; i <= 9; i++) {
        for(int j = 1; j <= 9; j++) {
            f[i][j] = 1;
            for(int k = 1; k <= j; k++) {
                f[i][j] *= i;
            }
        }
    }
//    for(int i = 6; ; i++) {
//        if(1LL * 1000000000 + W(i) > 1LL * f[9][9] * i) {
//            printf("%d\n", i); break;
//        }
//    } // max(bit) = 10

    for(int i = 0; i <= 100000; i++) {
        for(int k = 1; k <= 9; k++) {
            int n = i;
            sum[i][k] = 0;
            while(n) {
                sum[i][k] += f[n % 10][k];
                n /= 10;
            }
        }
    }
    int t, kcase = 1; scanf("%d", &t);
    while(t--) {
        int x, k; scanf("%d%d", &x, &k);

        LL ans = 0; int top = 0;
        for(int i = 0; i < 100000; i++) {
            val[i] = sum[i][k] - 1LL * i * 100000 - x;
            rec[top++] = val[i]; num[i] = 0;
        }
        sort(rec, rec + top); int N = top; top = 1;

        for(int i = 1; i < N; i++) {
            if(rec[i] != rec[i - 1]) {
                rec[top++] = rec[i];
            }
        }
        for(int i = 0; i < 100000; i++) {
            num[lower_bound(rec, rec + top, val[i]) - rec]++;
        }

        for(int i = 0; i < 100000; i++) {
            LL V = 1LL * i - sum[i][k];
            int p = lower_bound(rec, rec + top, V) - rec;
            if(rec[p] == V) {
                ans += num[p];
            }
        }
        if(x == 0) {
            ans--;
        }
        printf("Case #%d: %lld\n", kcase++, ans);
    }
    return 0;
}

F
注意考虑负数的情况,初始化0的活该WA

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
const int INF = 1e9 + 7;
typedef pair<int, int> pii;
char str[100];
int main()
{
    int t, kcase = 1; scanf("%d", &t);
    while(t--) {
        scanf("%s", str); int len = strlen(str);
        LL ans = -INF;
        for(int i = 0; i < len - 4; i++) {
            for(int j = i + 1; j < len - 3; j++) {
                LL a = 0;
                for(int k = 0; k <= i; k++) {
                    a = a * 10 + (str[k] - '0');
                }
                LL b = 0;
                for(int k = i + 1; k <= j; k++) {
                    b = b * 10 + (str[k] - '0');
                }

                LL c = str[j + 1] - '0';
                LL d = str[j + 2] - '0';
                LL e = 0;
                for(int k = j + 3; k < len; k++) {
                    e = e * 10 + (str[k] - '0');
                }
                ans = max(ans, a + b - c * d / e);
            }
        }
        printf("Case #%d: %lld\n", kcase++, ans);
    }
    return 0;
}

K
存在两个大于n的素数显然是不合法的,而且对于重叠的区间,最优方案是自己和自己匹配,这样就把点数优化到600的规模。跑匹配即可。n和s还可以写反?

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <stack>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
const int MOD = 1e9 + 7;
const int INF = 1e9 + 7;
typedef pair<int, int> pii;
vector<int> G[1000];
int match[1000];
bool used[1000];
bool DFS(int u) {
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if(!used[v]) {
            used[v] = true;
            if(match[v] == -1 || DFS(match[v])) {
                match[v] = u;
                return true;
            }
        }
    }
    return false;
}
void Solve(int n) {
    memset(match, -1, sizeof(match));
    int ans = 0;
    for(int i = 1; i <= n; i++) {
        memset(used, false, sizeof(used));
        ans += DFS(i);
    }
    printf(ans == n ? "Yes\n" : "No\n");
}
int main()
{
    int t, kcase = 1; scanf("%d", &t);
    while(t--) {
        int n, s; scanf("%d%d", &n, &s);
        printf("Case #%d: ", kcase++);
        if(s >= n) {
            if(n >= 600) {
                printf("No\n");
            }
            else {
                for(int i = 1; i <= n; i++) {
                    G[i].clear();
                    for(int j = 1; j <= n; j++) {
                        if((s + j) % i == 0) {
                            G[i].push_back(j);
                        }
                    }
                }
                Solve(n);
            }
        }
        else {
            if(s >= 600) {
                printf("No\n");
            }
            else {
                for(int i = 1; i <= s; i++) {
                    G[i].clear();
                    for(int j = 1; j <= s; j++) {
                        if((j + n) % i == 0) {
                            G[i].push_back(j);
                        }
                    }
                }
                Solve(s);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/chenzhenyu123456/article/details/52965642
今日推荐