某不知名的模拟赛题解DAY2

T1

题目大意

给你\(n\)个有0和1组成的字符串,然后要你用程序求出一个字符串,其中这个字符串的每一位上与之前输入的字符串的对应一位上的不同的字符的个数之和为相异度,我们要在满足所有相异度的和最小的情况下求出0的个数最多的字符串。

思路

由于相异度每一位都是独立的,所以题目中所有的相异度的和最小就是说明要使得每一位上的相异度最小。为了使每一位上的相异度最小我们需要统计所有输入的字符串当前位上的1的个数,若1的个数比0的个数多,那么就所求字符串这一位上的值就是1,如果0的个数比1多所求字符串这一位上就是0,如果0与1的个数相等,那么所求字符串的这一位上就应该是0(因为我们要在相异度之和最小的情况下满足0的数量最多)。

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e3 + 5;

int n, len;
int cnt[N];
char tmp[N];

vector <int> ans;

int main(int argc, char const *argv[]) {
    //从文件输入输出
    freopen("curse.in", "r", stdin);
    freopen("curse.out", "w", stdout);

    scanf("%d", &n);
    for (register int i = 1; i <= n; ++i) {
        scanf("%s", tmp + 1);
        len = strlen(tmp + 1);
        for (register int j = 1; j <= len; ++j) 
            if (tmp[j] == '1') ++cnt[j];
    }
    for (register int i = 1; i <= len; ++i) {
        if (cnt[i] > (n - cnt[i])) ans.push_back(1);
        else ans.push_back(0);
    }
    vector <int> :: iterator it;
    for (it = ans.begin(); it != ans.end(); ++it) 
        printf("%d", (*it));
    putchar('\n');
    return 0;
}

T2

题目大意

一个长度为\(1000000000\)的数轴上有\(n\)的点,然后我们有\(r\)个长度为\(l\)的线段和\(r\)个长度为 \(2 \times l\) 的线段去覆盖所有的点,现在\(n\),\(r\),\(g\)已知,求出\(l\)的最小值。

思路

这个题目中我们首先要注意到假如 \(r + g \ge n\) 那么就意味着每个线段长度为\(1\)即可覆盖所有的点。然后我们就可以二分出我们要求的长度,然后判断这个长度是否能够满足条件。

我们要怎么判断一个当\(l\)为某个值的时候可以覆盖所有的点。我们可以设\(dp[i][j]\)为用了\(i\)个较短的线段\(j\)个较长的线段可以从1开始连续覆盖多少个点,然后我们就可以得到一个转移方程:

\[ dp[i][j] = max(dp[p[i - 1][j] + 1], dp[q[i][j - 1] + 1]) \]

其中\(p[i]\)是指从第i个点开始用了一次较短的线段能够覆盖到的点的编号(不是个数),然后\(q[i]\)指的是从\(i\)个点开始能够覆盖到的点的编号。\(p\),\(q\)这两个数组可以在进行dp转移前预处理出来。

要注意的地方

首先要注意\(dp\)数组的初始化。我们一定要在枚举\(i\)\(j\)之后先将\(dp[i][j]\)清零再进行方程的转移,要不然之前二分留下的\(dp\)数组里的值可能会让方程无法正常转移。
然后要注意\(i\)\(j\)为0的情况,同时要注意\(i\)\(j\)为0的情况中不只是有\(dp[1][0]\)\(dp[0][1]\)两种情况。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 2e3 + 5;

int n, g, r;
int a[N];
int ans;
int q[N], p[N];
int dp[N][N];

int read() {
    int s = 0, w = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')  w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        s = s * 10 + ch - '0';
        ch = getchar();
    }
    return s * w;
}

void write(int x) {
    if (x < 0) putchar('-'), x = -x;
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

inline int Max(int x, int y) {
    return x >= y ? x : y;
}

inline int Min(int x, int y) {
    return x <= y ? x : y;
}

bool check(int x) {
    for (register int i = 1; i <= n; ++i) { //预处理p, q
        register int j;
        for (j = i; j <= n && a[j] - a[i] + 1 <= x; ++j) 
            p[i] = j;
        for (j = i; j <= n && a[j] - a[i] + 1 <= x * 2; ++j) 
            q[i] = j;
    }
    p[n + 1] = n;
    q[n + 1] = n;
    for (register int i = 0; i <= r; ++i) {
        for (register int j = 0; j <= g; ++j) {
            dp[i][j] = 0; //这里很重要
            if (i > 0) dp[i][j] = Max(dp[i][j], p[dp[i - 1][j] + 1]);
            if (j > 0) dp[i][j] = Max(dp[i][j], q[dp[i][j - 1] + 1]); //这里很重要
        }
    }
    if (dp[r][g] == n) return true;
    else return false;
}

void fuc(int lc, int rc) {
    if (lc > rc) return;
    int mid = (lc + rc) >> 1;
    if (check(mid)) ans = mid, fuc(lc, mid - 1);
    else fuc(mid + 1, rc);
}

int main(int argc, char const *argv[]) {
    //从文件输入输出
    freopen("light.in", "r", stdin);
    freopen("light.out", "w", stdout);

    n = read(), r = read(), g = read();
    for (register int i = 1; i <= n; ++i) 
        a[i] = read();
    sort(a, a + 1 + n);
    if (r + g >= n) {
        write(1), putchar('\n');
        return 0;
    }
    fuc(1, 1000000000);
    write(ans), putchar('\n');
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lixiao189/p/9851882.html
今日推荐