Codeforces Round #352 (Div. 2)

模拟 A - Summer Camp

#include <bits/stdc++.h>

int a[1100];
int b[100];
int len;

void init() {
    int i = 1, tot = 1;
    while (tot <= 1010) {
        int t = i, c = 0;
        while (t) {
            b[c++] = t % 10;
            t /= 10;
        }
        for (int i=c-1; i>=0; --i) {
            a[tot++] = b[i];
        }
        i++;
    }
}

int main() {
    init ();
    int n; scanf ("%d", &n);
    printf ("%d", a[n]);
    return 0;
}

构造 B - Different is Good

题意:问最少改变多少个字母使得该字符串的所有子串不相同

分析:子串有长度为1的,所以如果字符串长度大于26一定不可行,否则就把相同的字母用没出现的字母替换.

#include <bits/stdc++.h>

const int N = 1e5 + 5;
char str[N];
int vis[30];

int main() {
    int n; scanf ("%d%s", &n, str);
    if (n > 26) {
        puts ("-1");
    } else {
        int ans = 0;
        for (int i=0; i<n; ++i) {
            if (vis[str[i]-'a']) {
                ans++;
            } else {
                vis[str[i]-'a'] = true;
            }
        }
        printf ("%d
", ans);
    }
    return 0;
}

几何+贪心 C - Recycling Bottles

题意:A和B捡罐头,每次只能捡一个然后到垃圾桶去,再从垃圾桶出发去捡,问捡完所有罐头所需的最少总路程

分析:除从A或B出发第一次捡罐头的距离不确定外,其他的都可以看成sum (dis (T, p[i]) *2),所以只需要 min (-dis (T, p[i]) + dis (A, p[i])).因为A和B捡罐头是独立的,只要A和B都捡一个罐头使得差值最小,重复时特判下就行了.更一般的做法是A任意选择一个罐头,B选择除A选的外里最小差值的那一个,可以预处理出前缀最小和后缀最小.

#include <bits/stdc++.h>

const int N = 1e5 + 5;
const double INF = 1e18 + 5;
const double EPS = 1e-8;
struct Point {
    double x, y;
    Point() {}
    Point(double x, double y) {
        this->x = x;
        this->y = y;
    }
}point[N];
Point A, B, O;
double dis[N];
double sum;
double pre[N], suff[N];
double add[N];
int n;

Point read_point() {
    double x, y; scanf ("%lf%lf", &x, &y);
    return Point (x, y);
}

double squ(double x) {
    return x * x;
}

double calc_dis(Point a, Point b) {
    return sqrt (squ (a.x - b.x) + squ (a.y - b.y));
}

int main() {
    A = read_point ();
    B = read_point ();
    O = read_point ();
    scanf ("%d", &n);
    for (int i=1; i<=n; ++i) {
        point[i] = read_point ();
        dis[i] = calc_dis (point[i], O);
        pre[i] = suff[i] = -dis[i] + calc_dis (point[i], B);
        add[i] = -dis[i] + calc_dis (point[i], A);
        sum += dis[i] * 2;
    }
    pre[0] = suff[n+1] = INF;
    for (int i=1; i<=n; ++i) {
        pre[i] = std::min (pre[i], pre[i-1]);
    }
    for (int i=n; i>=1; --i) {
        suff[i] = std::min (suff[i], suff[i+1]);
    }
    double ans = sum + suff[1];  //just B
    for (int i=1; i<=n; ++i) {
        ans = std::min (ans, sum + std::min (0.0, std::min (pre[i-1], suff[i+1])) + add[i]);
    }
    printf ("%.12f
", ans);
    return 0;
}

二分 D - Robin Hood

题意:n个人,k次操作,每次把最大的数分1到最小的数,问k次后最大值和最小值的差

分析:二分最小值和最大值,思想是求出min(max) 刚好使得小于它的到它的操作正好是k.处理好二分的边界,因为二分时是尽量使得最小值大,最大值小.

#include <bits/stdc++.h>

typedef long long ll;
const int N = 5e5 + 5;
int a[N];
int n, k;

bool check(int val, int op) {
    ll need = 0;
    for (int i=0; i<n; ++i) {
        if (op == 1) {
            if (a[i] <= val) {
                need += val - a[i];
            } else {
                break;
            }
        } else if (op == 2 && a[i] >= val) {
            need += a[i] - val;
        }
    }
    return need <= k;
}

int main() {
    scanf ("%d%d", &n, &k);
    ll sum = 0;
    for (int i=0; i<n; ++i) {
        scanf ("%d", a+i);
        sum += a[i];
    }
    std::sort (a, a+n);
    int ansl = -1, ansr = 1e9;
    int left = a[0], right = sum / n;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (check (mid, 1)) {
            ansl = mid;
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    left = sum / n;
    if (sum % n) {
        left++;
    }
    right = a[n-1];
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (check (mid, 2)) {
            ansr = mid;
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    printf ("%d
", ansr - ansl);
    return 0;
}

  

原文地址:https://www.cnblogs.com/Running-Time/p/5491122.html