zoukankan      html  css  js  c++  java
  • Codeforces Round #710 (Div. 3) A B C D E

    第一次过五道题目,但是起手慢了,相对于其他选手的优势也很小.最后和平时的排名百分比没什么区别.

    E题的通过人数是三千,到了F题只剩500形成断崖,所以想突破一道百人题对我还是很难.

    码量是有一点的(因为平时div2太弱最多写到三题),基本上是在面向AC做题,使用各种基本技巧就可以了,处理起来需要稍加思考.

    做完E题差不多只有十分钟了,这个手速肯定欠练.

    早上一看发现E被hack了,持续掉分.= =


    A

    草稿纸上面计算一下在Colum模式下数字x所处的第i行,第j列,然后计算出在rows模式下第i行,第j列的数字即可.

    主要用到取模和向上取整的整除.

    我花了接近20分钟,打草稿的效率太低了,一直出错.

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    long long n, m, x;
    
    void solve(){
        scanf("%lld%lld%lld", &n, &m, &x);
        long long i = x % n;
        long long j = (x - 1) / n + 1;
        if(!i) i = n;
        if(!j) j = m;
    
        printf("%lld
    ", (i - 1) * m + j);
    }
    
    int main(){
        int t;
        scanf("%d", &t);
        while(t--) solve();   
    
        return 0;
    }
    A

    B

    数据保证有解.

    按照题意模拟即可,先将第一个*改为x,之后维护上一个x的位置last,检测到 . 则跳过,检测到*且位置距离last大于k时,向前查找一个*满足其位置与last相差不大于k,将其改为x并更新last.

    最后检查一下末端是否满足最后一个*改为了x.

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <string>
    using namespace std;
    
    int n, k;
    string s;
    
    void solve() {
        cin >> n >> k >> s;
        bool hd = false;
        int last = 0, ans = 0;
        for (int i = 0; i < s.size(); i++) {
            if(s[i] == '.') continue;
            if(!hd){
                s[i] = 'x';
                last = i;
                hd = true;
                ans++;
                continue;
            }
            while(i - last > k){
                int p = i;
                while(p - last > k || s[p] != '*') p--;
                last = p;
                s[p] = 'x';
                ans++;
            }
        }
        for(int i = s.size() - 1; i >= 0; i--)
            if(s[i] == 'x') break;
            else if(s[i] == '*'){
                ans++;
                break;
            }
    
        printf("%d
    ", ans);
    }
    
    int main() {
        int t;
        scanf("%d", &t);
        while (t--) solve();
    
        return 0;
    }
    B

    C

    数据范围惊人地小,那么可以O(N2)对比,找到两字符串能匹配的最大长度,然后让其保留此长度的字符串并删除其余字符,需要的总操作数显然是(a的长度)+(b的长度)-2*(匹配的最长字符串的长度).

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <string>
    using namespace std;
    
    string a, b;
    
    void solve() {
        cin >> a >> b;
        int big = 0;
        for (int i = 0; i < a.size(); i++) {
            for (int j = 0; j < b.size(); j++) {
                int ct = 0;
                int p1 = i, p2 = j;
                while (p1 < a.size() && p2 < b.size() && a[p1] == b[p2]) {
                    ct++;
                    p1++;
                    p2++;
                }
    
                big = max(big, ct);
            }
        }
        printf("%d
    ", a.size() + b.size() - 2 * big);
    }
    
    int main() {
        int t;
        scanf("%d", &t);
        while (t--) solve();
    
        return 0;
    }
    C

    D

    应该是前五题里最麻烦的吧.

    我维护了一个数组rkct[i],其值为rank为i的数字(也就是离散化)出现的次数.数组的顺序是无关紧要的,可以舍弃这个信息.

    也不需要关系rank为i的数字是谁,所以干脆再把rkct数组也升序排列,看起来更好操作.

    想到过几种方法都没找到出路:

      让rkct从两端相互抵消,不能处理112233,但可以处理11223333.

      让rkct不停从左到右,相邻项抵消,可以处理112233,但不能处理11223333.

    发现这两种方法分别解决了一个问题,于是有所启发:

      ①从首个数字不停地顺序,循环取走,直至下一个要取的数字会与上一个相同.

        如11223333依次取出123123,剩下33.

        会发现这时剩下的数字只会是出现次数最多的数字.

      ②将剩下的数字插入到取出的序列.

        即将两个3插入到先前得到的123123中,这很容易做到,可以计算出可插入点(用0表示)010231023有三个.

    最后仍然可能有数字剩下,这时就需要直接统计到答案里了.

    注意,由于是两两消除,数组元素数量却会出现奇数情况,这只需要在最后处理答案时进行考虑.

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <vector>
    using namespace std;
    
    int n, a[200010], rkct[200010];
    vector<int> v;
    
    void solve(){
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) scanf("%d", a + i), rkct[i] = 0;
        sort(a + 1, a + n + 1);
        v.clear();
    
        int cur = a[1], ind = 1;
        for(int i = 1; i <= n; i++){
            if(a[i] == cur) rkct[ind]++;
            else cur = a[i], rkct[++ind]++;
        }
        if(ind == 1) {printf("%d
    ", rkct[1]); return;}
        sort(rkct + 1, rkct + ind + 1);
    
        int l = 1;
        while(rkct[ind - 1]){
            for(int i = l; i <= ind; i++){
                rkct[i]--;
                v.push_back(i);
            }
            while(!rkct[l]) l++;
        }
        int spa = 0;
        for(int i = 0; i < v.size(); i++)
            if(v[i] != ind && (i == 0 || v[i - 1] != ind))
                spa++;
    
        if(rkct[ind] <= spa){
            printf("%d
    ", (v.size() + rkct[ind]) % 2);
        }else{
            int ans = (v.size() + spa) % 2;
            printf("%d
    ", ans + rkct[ind] - spa);
        }
        // for(int i = 1; i <= ind; i++) printf("_%d ", rkct[i]);
        // puts("");
    }
    
    int main(){
        // freopen("in.txt", "r", stdin);
        int t;
        scanf("%d", &t);
        while(t--) solve();   
    
        return 0;
    }
    D

    E

    对于数据给定的序列,若q[i]!=q[i-1],说明位置i一定为q[i].

    依次可以确定出所有固定的点,剩下的未使用的点构成一个集合.

    想要得到最小字典序很简单,从这个集合中不停取走最小者安排到空缺的位置即可.

    别看这段↓

    而想要得到最大字典序,对于未确定的位置i,插入的值范围为[1,q[i]-1],从q[i]-1一直递减,检查到第一个未使用值时将其插入并标记为已使用即可.

    这个过程花费的时间复杂度我没有细算,但是TLE了.

    加了了记忆化,数组big[x]表示小于x且可能 未使用的最大值,每当发现某个q[i]=x的点插入了值p,就将big[x]更新为p-1.

    由于只是可能未使用,还是要不停向下检查直到找到确实未使用的值.

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    int n, q[200010], ans[200010];
    int big[200010];
    bool used[200010], tused[200010];
    
    void solve() {
        memset(used, 0, sizeof(used));
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", q + i);
            big[q[i]] = q[i] - 1;
            ans[i] = 0;
            if (q[i] != q[i - 1]) {
                ans[i] = q[i];
                used[q[i]] = true;
            }
        }
    
        int p = 1;
        memcpy(tused, used, sizeof(used));
        for (int i = 1; i <= n; i++) {
            if (ans[i])
                printf("%d ", ans[i]);
            else {
                while (tused[p]) p++;
                tused[p] = true;
                printf("%d ", p);
            }
        }
        puts("");
    
        for(int i = 1; i <= n; i++){
            if(ans[i]) printf("%d ", ans[i]);
            else{
                int p = big[q[i]];
                while(used[p]) p--;
                used[p] = true;
                big[q[i]] = p - 1;
                printf("%d ", p);
            }
        }
        puts("");
    }
    
    int main() {
        int t;
        scanf("%d", &t);
        while (t--) solve();
    
        return 0;
    }
    E Hacked

    醒醒,这个复杂度仍然是O(N2),你被hack了.

    正确的求最大字典序方法是二分找值插入.

    使用set,这个数据结构可以按值删除元素,也可以二分查找.

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <set>
    using namespace std;
    
    int t, n;
    int a[200010];
    set<int> s;
    
    void solve() {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]), s.insert(i);
    
        for (int i = 1; i <= n; i++) {
            if (a[i] != a[i - 1])
                printf("%d ", a[i]), s.erase(a[i]);
            else
                printf("%d ", *s.begin()), s.erase(s.begin());
        }
        puts("");
    
        for (int i = 1; i <= n; i++) s.insert(i);
        for (int i = 1; i <= n; i++) {
            if (a[i] != a[i - 1])
                printf("%d ", a[i]), s.erase(a[i]);
            else {
                auto it = prev(s.lower_bound(a[i]));
                printf("%d ", *it);
                s.erase(it);
            }
        }
        puts("");
    }
    
    int main() {
        int t;
        scanf("%d", &t);
        while (t--) solve();
    
        return 0;
    }
    E
  • 相关阅读:
    内置函数
    json && pickle 反序列化
    装饰器(语法糖)
    shell环境改变引起的命令提示符改变
    FTP服务安装与端口说明
    tomcat配置
    greenDao 中连接查询
    COM组件DLL引用时出现检索组件错误
    VS 调试断点命中了,程序无法再断点处中断
    单点登录原理与简单实现
  • 原文地址:https://www.cnblogs.com/Gaomez/p/14580070.html
Copyright © 2011-2022 走看看