Codeforces Round #704 DIv.2 A B C D

今天难得是在白天比赛.过三题,一边写着看到都已经过了system test了,D题还是WA在最后的pretest了,之后再补上.

Codeforces Round #704 DIv.2 A B C D

 

 


 

A

手快就行,写得多垃圾能AC就好.记得long long,再记得把中间的临时变量也开long long.

Codeforces Round #704 DIv.2 A B C D
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

long long p, a, b, c;

void solve(){
    cin >> p >> a >> b >> c;
    long long na = a, nb = b, nc = c;
    na += ((p - a) / a) * a;
    nb += ((p - b) / b) * b;
    nc += ((p - c) / c) * c;
    while(na < p) na += a;
    while(nb < p) nb += b;
    while(nc < p) nc += c;

    cout << min({na, nb, nc}) - p << endl;
}

int main(){
    int t;
    scanf("%d", &t);
    while(t--) solve();   

    return 0;
}
A

 

B

花里胡哨地绕了半天,其实这个在暗示你进制的东西:

Codeforces Round #704 DIv.2 A B C D

其实等价于字典序大小.

比如这个数据:

4 2 5 3 6 1

不停地选一个位置截断到末尾,并把接下来的序列顺序尾首拼接,要让得到的序列字典序最大,那很明显了,不停从最大值处截取,依次得到子序列:

6 1
5 3
4 2

 顺序连接起来即为答案.

复杂度要做点处理,代码有点乱了.

Codeforces Round #704 DIv.2 A B C D
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

int n, p[100010], pos[100010];
bool used[100010], numused[100010];

void solve() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", p + i);
        pos[p[i]] = i;
    }
    memset(used, 0, sizeof(used));
    memset(numused, 0, sizeof(numused));
    int cur = n;
    used[n + 1] = true;
    while (cur >= 1) {
        if (numused[cur]) {
            cur--;
            continue;
        }
        for (int i = pos[cur]; !used[i]; i++) {
            if (p[i] == cur) {
                for (int j = i; !used[j]; j++) {
                    used[j] = true;
                    numused[p[j]] = true;
                    printf("%d ", p[j]);
                }
            }
        }
        cur--;
    }

    puts("");
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) solve();

    return 0;
}
B

 

C

一开始想到的是把t的每一个字符的最早出现位置和最晚出现位置都记录下来,然后扫描一遍 t 并检查相邻字符中后者最晚出现位置与前者最早出现位置之差,最大值为解,但是很显然直接这么做是不能保证这些位置是满足字符串是beautiful的条件的.

(插播,system test结束了,D竟然FST了差不多四分之一成为百人题)

所以,先用双指针从左到右扫描 s 和 t ,只有匹配时记录这个字符的位置,这时记录的是满足beautiful的最早出现位置.

然后同样地,从右到左再来一遍,现在记录的就是满足beautiful的最晚出现位置.

现在就可以检查相邻字符的最大差了.

Codeforces Round #704 DIv.2 A B C D
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
using namespace std;

typedef pair<int, int> P;
string s1, s2;
int l1, l2;
P pos[200010];

int main(){
    cin >> l1 >> l2 >> s1 >> s2;
    int p = 0;
    for(int i = 0; p < s2.size() && i < s1.size(); i++)
        if(s1[i] == s2[p]){
            pos[p].first = i;
            p++;
        }
    p--;
    for(int i = s1.size() - 1; p >= 0 && i >= 0 ; i--)
        if(s1[i] == s2[p]){
            pos[p].second = i;
            p--;
        }

    int ans = 0;
    for(int i = 0; i < s2.size() - 1; i++)
        ans = max(ans, pos[i + 1].second - pos[i].first);
    // for(int i = 0; i < s2.size(); i++){printf("%d %d\n", pos[i].first, pos[i].second);}
    cout << ans << endl;

    return 0;
}
C

 

D

构造题,从剩下一个小时十分钟到结束都在看,也没调出来.

已经可以看到测试点了,看了最后一个pretest才发现我末尾处的处理完全就是错的(我还一直在想边界情况),那前17个测试点是不是太水了?

Codeforces Round #704 DIv.2 A B C D

 

现有的思路是正确的:

设z=x-y,则x=y+z.

x,y都有a个0和b个1,并且y加上一个二进制数后变为x,仍然是a个0和b个1.

这意味着z的某一位加到y的对应位上,可以恰好使得y此位进位变为0,且高一位因此从0变为1.

所以想到把y假定为10...01...1,省略号及两端依次表示1个0和b-1个1,比如假定y为:

1000111

现在尝试在某一位上加一,使得结果的0和1个数不变,显然只有一个位置:

  1000111
+     100
------------
  1001011

如果z=100,那么x就是1001011,此时k=1,有解.

如果在原y基础上的另一位上额外再加一,仍不改变0和1的个数,有两个位置可选,比如选择靠前的位置:

  1000111
+    1100
------------
  1010011

会发现相对原y把"1"左移了两位,此时z=1100,x=1010011,k=2,有解.

你可以把这个"1"继续左移直到其左边没有0,此后你可以把下一个"1"通过这样的操作继续左移直到其左侧没有0,要注意的是z的每一位只能用一次,用后那一位就已经是1,不能再加了.观察之后会发现有解的条件是a + b - 2 >= k.

更要注意的是,决定z的某一位是否为1需要按照顺序来,比如想把100111加到111100,随着k的递增,变为1的位需要按照如下顺序:

k=1: z=100

k=2: z=1100

k=3: z=1110

k=4: z=1111

这遵循着把"1"不断地"搬运"到最左侧的过程.如果无序地处理会导致意外地多次进位改变0和1的数量.(我就是没考虑顺序WA的)

 

现在考虑边界情况,有两种,a=0和b=1,两种情况下都是只有k=0时才会有解,很容易处理.

由于位数很多,我开了个数组手动模拟二进制.

已经AC.

Codeforces Round #704 DIv.2 A B C D
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;

long long a, b, k;
int x[200010], y[200010];
bool z[200010];

int main() {
    cin >> a >> b >> k;
    memset(z, 0, sizeof(z));
    if (b <= 1) {
        if (k) {
            cout << "No" << endl;
            return 0;
        } else
            cout << "Yes" << endl;
    } else if (!a) {
        if (k) {
            cout << "No" << endl;
            return 0;
        } else
            cout << "Yes" << endl;
    } else if (a + b - 2 >= k)
        cout << "Yes" << endl;
    else {
        cout << "No" << endl;
        return 0;
    }

    x[a + b] = y[a + b] = 1;
    for (int i = 1; i <= a + b - 1; i++) {
        if (i <= b - 1)
            y[i] = 1;
        else
            y[i] = 0;
        x[i] = y[i];
    }

    int t = k, hd = b - 1, ed = a + b - 2;
    while(t){
        for(int i = hd; i <= ed && t; t--, i++)
            z[i] = true;
        hd--;
        ed = hd;
    }
    for (int i = 1; i <= a + b; i++) {
        if (x[i] == 2) x[i] = 0, x[i + 1]++;
        if(z[i]) x[i]++;
        if (x[i] == 2) x[i] = 0, x[i + 1]++;
    }

    for (int i = a + b; i >= 1; i--) cout << x[i];
    cout << endl;
    for (int i = a + b; i >= 1; i--) cout << y[i];
    cout << endl;

    return 0;
}
D
上一篇:704. 二分查找


下一篇:Codeforces Round #704 (Div. 2)