Codeforces #311(div2)

A. Ilya and Diplomas

题意: 找到三个数 使得满足在三个范围之间 并且和为n 多种可能使得 第一个数尽可能大 第二个数尽可能大

思路: 按题意枚举一下

参考code:

//
//  Created by TaoSama on 2015-06-30
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, a[3][2];

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    while(cin >> n) {
        for(int i = 0; i < 3; ++i) for(int j = 0; j < 2; ++j) cin >> a[i][j];
        int sum = a[1][0] + a[2][0];
        bool ok = false;
        int ans[3];
        for(int i = min(n - sum, a[0][1]); i >= a[0][0]; --i) {
            for(int j = min(n - i - a[2][0], a[1][1]); j >= a[1][0]; --j) {
                if(n - i - j >= a[2][0] && n - i - j <= a[2][1]) {
                    ok = true;
                    ans[0] = i; ans[1] = j; ans[2] = n - i - j;
                    break;
                }
            }
            if(ok) break;
        }
        for(int i = 0; i < 3; ++i) cout << ans[i] << ' ';
        cout << '\n';
    }
    return 0;
}

B. Pasha and Tea
题意: 一个茶壶可以烧不超过w的水 给女生分配杯子 然后给男女生倒水 必须都有水 且每个男生水相等 每个女生相等 且每个男生水是女生的2倍
思路: 排序一下 从大到小 不断给男女生分配水 二分check一下就可以了
参考code:
//
//  Created by TaoSama on 2015-06-30
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 2e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, w, a[N];

bool check(double x) {
    double e = x / 3.0 / n;
    for(int i = n << 1; i; --i) {
        if(i > n) {
            if(a[i] < 2 * e) return false;
        } else {
            if(a[i] < e) return false;
        }
    }
    return true;
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    while(cin >> n >> w) {
        for(int i = 1; i <= n << 1; ++i) cin >> a[i];
        sort(a + 1, a + 1 + (n << 1));
        double l = 0, r = w;
        for(int i = 1; i <= 100; ++i) {
            double mid = (l + r) / 2.0;
            if(check(mid)) l = mid;
            else r = mid;
        }
        cout << fixed << setprecision(12) << l << endl;
    }
    return 0;
}

C. Arthur and Table

题意: 一个椅子n条腿 删掉每条腿有个各自的体力 平衡的条件是 最长的腿的个数必须占一半以上 求使椅子平衡的最小体力花费
思路: 枚举每条腿作为最长腿 假设它的个数是x  然后删掉所有比它长的 删掉一些比它短的(留下x-1个就好) 贪心的思路
这样看上去像时候n^2的  考虑优化 我们可以直接算出来比它长的腿的花费和 用前缀和就好了
然后发现d只有200  我们对腿长排序 在枚举腿长的时候 然后不断更新d的cnt数组 这样cnt数组里都是比这条腿小的  删除的时候从最小的开始贪心的删除
这样复杂度就优化到了 O(d * n)了
参考code:
//
//  Created by TaoSama on 2015-06-30
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, d[205], l[N], sum[N];
pair<int, int> a[N];

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    while(cin >> n) {
        memset(d, 0, sizeof d);
        memset(l, 0, sizeof l);
        for(int i = 1; i <= n << 1; ++i) {
            if(i <= n) {
                cin >> a[i].first;
                l[a[i].first]++;
            } else {
                cin >> a[i - n].second;
            }
        }
        sort(a + 1, a + 1 + n);

        for(int i = 1; i <= n; ++i)
            sum[i] = sum[i - 1] + a[i].second;

//      for(int i = 1; i <= n; ++i){
//          pr(a[i].first); pr(a[i].second); prln(sum[n] - sum[i]);
//      }

        int ans = INF;
        for(int i = 1; i <= n; ++i) {
            int t = i + l[a[i].first];
            int cur = sum[n] - sum[t - 1];

            for(int j = 1, k = i - l[a[i].first]; j <= 200 && k > 0; ++j) {
                if(k >= d[j]) cur += j * d[j], k -= d[j];
                else cur += j * k, k = 0;
            }
//            prln(cur);
//            for(int j = 1; j <= 200; ++j){
//              if(d[j]) pr(j), prln(d[j]);
//          }
//          cout << endl;
            ans = min(ans, cur);
            for(int j = i; j < t; ++j) d[a[j].second]++;
            i = t - 1;
        }
        cout << ans << '\n';
    }
    return 0;
}
/*
2
1 5
3 2
3
2 4 4
1 1 1
6
2 2 1 1 3 3
4 3 5 5 2 1
*/

D. Vitaly and Cycle
题意: 一个没有重边和自环的无向图 可能不连通 求添加最少的边使得这个图存在一个奇数长度的回路的 边数 和 方法数

思路: 一个奇回路的边数最少是3  那么这个题的边数答案应该是 [0,3]

考虑 3的方法数 这个时候图应该是没有边 全是散点 那么方法数应该是 C_n_3 (n个点里选3个点连3条边)  m = 0

考虑 2的方法数 这个时候图应该是 必然有2个点构成的长度为1的链(边) 以及 可能有多余的散点  这时候每个点度数都<=1

将这条边向任意其它1点连2条边 构成奇回路 方法数是C_n-2_1(n-2点里选1点连2条边)

考虑 1的方法数 这个时候图应该是 有大于2点构成的连通分量 这个时候用二分图染色 如果可以染色说明 只有偶回路

不然有奇回路 就是添加0条边了  方法数 对于每个连通分量任意两个相同颜色连1条边 

所以都是 C_cnt_2  ans1 += cnt1 * (cnt1 - 1) / 2 + cnt2 * (cnt2 - 1) / 2.

考虑 0的方法数 显然只有不加这一种方法 所以是1

参考code:

//
//  Created by TaoSama on 2015-06-30
//  Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, m, c[N];
long long ans[5], cnt[2];
vector<int> G[N];

bool dfs(int u, int cc) {
    c[u] = cc; cnt[cc]++;
    for(int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i];
        if(c[v] == cc) return false;
        if(c[v] == -1 && !dfs(v, cc ^ 1)) return false;
    }
    return true;
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    while(cin >> n >> m) {
        for(int i = 1; i <= n; ++i) G[i].clear();
        for(int i = 1; i <= m; ++i) {
            int u, v; cin >> u >> v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        memset(c, -1, sizeof c);
        memset(ans, 0, sizeof ans);

        if(m == 0) ans[3] = 1LL * n * (n - 1) * (n - 2) / 6;

        bool two = true;
        for(int i = 1; i <= n; ++i) two &= G[i].size() <= 1;
        if(two) ans[2] = 1LL * m * (n - 2);

        bool zero = false;
        for(int i = 1; i <= n; ++i) {
            memset(cnt, 0, sizeof cnt);
            if(c[i] == - 1 && !dfs(i, 0)) {
                zero = true;
                break;
            } else ans[1] += cnt[0] * (cnt[0] - 1) / 2 + cnt[1] * (cnt[1] - 1) / 2;
        }

        if(zero) cout << "0 1\n";
        else if(ans[1]) cout << 1 << ' ' << ans[1] << '\n';
        else if(ans[2]) cout << 2 << ' ' << ans[2] << '\n';
        else cout << 3 << ' ' << ans[3] << '\n';
    }
    return 0;
}

E. Ann and Half-Palindrome

题意: 求|s|<=5000 的只有奇数位置是回文的 字典序的第k个字串

思路: 填坑

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值