• Educational Codeforces Round 48 (Rated for Div. 2)


    又是回忆场。

    A - Death Note

    题意:有一本笔记,你在第i天连续写ai个字,每写满m个字强制翻页(不管还要不要写),求第i天翻了多少页。

    题解:那么当前的页数就是下整+1(其实不加也可以,从0开始),直接模拟即可,我当时写的什么东西?

    注意溢出。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    void test_case() {
        int n, m;
        scanf("%d%d", &n, &m);
        ll cur = 0, px = 1;
        for(int i = 1; i <= n; ++i) {
            int ai;
            scanf("%d", &ai);
            cur += ai;
            ll cx = (cur / m) + 1;
            printf("%lld%c", cx - px, " 
    "[i == n]);
            px = cx;
        }
    }
    
    int main() {
    #ifdef KisekiPurin
        freopen("KisekiPurin.in", "r", stdin);
    #endif // KisekiPurin
        int t = 1;
        for(int ti = 1; ti <= t; ++ti) {
            //printf("Case #%d: ", ti);
            test_case();
        }
    }
    

    B - Segment Occurrences

    题意:给定两个字符串s,t,询问q次,每次询问s的子串[l,r]中出现了t多少次。

    题解:很明显用KMP可以做,不能再鸽KMP了,弄个next数组,求出匹配的位置,然后差分打上标记,出现的次数就是(减去长度差异之后的)前缀和的差。

    学了一个KMP,看起来还蛮对的样子,可以返回所有匹配的位置,特点是都是从0开始。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int pi[1005];
    void GetPrefixFunction(char *s, int sl) {
        pi[0] = 0, pi[1] = 0;
        for(int i = 1, k = 0; i < sl; ++i) {
            while(k && s[i] != s[k])
                k = pi[k];
            pi[i + 1] = (s[i] == s[k]) ? ++k : 0;
        }
    }
    
    //返回t在s中所有occurrence的首地址,s和t都是从0开始的
    int ans[1005], atop;
    void KMP(char *s, int sl, char *t, int tl) {
        GetPrefixFunction(t, tl);
        atop = 0;
        for(int i = 0, k = 0; i < sl; ++i) {
            while(k && s[i] != t[k])
                k = pi[k];
            k += (s[i] == t[k]);
            if(k == tl)
                ans[++atop] = i - tl + 1;
        }
    }
    
    char s[1005], t[1005];
    int prefix[1005];
    
    void test_case() {
        int n, m, q;
        scanf("%d%d%d", &n, &m, &q);
        scanf("%s%s", s + 1, t + 1);
        KMP(s + 1, n, t + 1, m);
        for(int i = 1; i <= atop; ++i)
            ++prefix[ans[i] + 1];
        for(int i = 1; i <= n; ++i)
            prefix[i] += prefix[i - 1];
        while(q--) {
            int l, r;
            scanf("%d%d", &l, &r);
            if(r - l + 1 < m) {
                puts("0");
                continue;
            }
            printf("%d
    ", prefix[r - m + 1] - prefix[l - 1]);
        }
    }
    
    int main() {
    #ifdef KisekiPurin
        freopen("KisekiPurin.in", "r", stdin);
    #endif // KisekiPurin
        int t = 1;
        for(int ti = 1; ti <= t; ++ti) {
            //printf("Case #%d: ", ti);
            test_case();
        }
    }
    

    C - Vasya And The Mushrooms

    题意:有一个2*n的格子矩阵,从左上角出发,必须遍历每个格子恰好一次,求最大的分数。每个格子会长一种蘑菇,这种蘑菇有它的生长速度,每次移动没被遍历的格子的蘑菇就会生长这个积分。

    题解:一旦在另一行的格子没有被遍历时,开始选择向右走,则会必须走到尽头然后折返。那么可以计算出这样做的总收益。否则要走向另一个格子,然后转移到下一列的决策。看起来就很dp!设dp[i][0/1]为从第i列的上/下开始走,遍历完右侧所有格子的最大收益。倒过来转移,每次转移分两种情况,(在上方时)一种是往下走然后加上右下角的dp值,还有因为这两步而增长的2倍后缀0的积分,另一种是直接往右走收掉后缀1的积分,然后到尽头转头收掉后缀2的积分,同时加上走后缀1时后缀2增长的积分。看起来很像我第一次学线段树的那道题。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    ll a[300005][2];
    ll suffix0[300005][2];
    ll suffix1[300005][2];
    ll suffix2[300005][2];
    ll dp[300005][2];
    
    void test_case() {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
            scanf("%lld", &a[i][0]);
        for(int i = 1; i <= n; ++i)
            scanf("%lld", &a[i][1]);
        for(int i = n; i >= 1; --i) {
            suffix0[i][0] = suffix0[i + 1][0] + a[i][0];
            suffix0[i][1] = suffix0[i + 1][1] + a[i][1];
            suffix1[i][0] = suffix1[i + 1][0] + suffix0[i + 1][0] + a[i][0];
            suffix1[i][1] = suffix1[i + 1][1] + suffix0[i + 1][1] + a[i][1];
            suffix2[i][0] = suffix2[i + 1][0] + 1ll * (n - i + 1) * a[i][0];
            suffix2[i][1] = suffix2[i + 1][1] + 1ll * (n - i + 1) * a[i][1];
        }
    
        for(int i = n; i >= 1; --i) {
            dp[i][0] = max(dp[i + 1][1] + 2ll * suffix0[i + 1][0] + 2ll * suffix0[i + 1][1] + a[i][1], suffix1[i + 1][0] + suffix2[i][1] + 1ll * (n - i) * suffix0[i][1]);
            dp[i][1] = max(dp[i + 1][0] + 2ll * suffix0[i + 1][1] + 2ll * suffix0[i + 1][0] + a[i][0], suffix1[i + 1][1] + suffix2[i][0] + 1ll * (n - i) * suffix0[i][0]);
        }
    
        printf("%lld
    ", dp[1][0]);
    }
    
    int main() {
    #ifdef KisekiPurin
        freopen("KisekiPurin.in", "r", stdin);
    #endif // KisekiPurin
        int t = 1;
        for(int ti = 1; ti <= t; ++ti) {
            //printf("Case #%d: ", ti);
            test_case();
        }
    }
    

    D - Vasya And The Matrix

    题意:给n行的异或和,m列的异或和,把这个矩阵复原出来,或者告知无解。

    题解:这种题貌似都可以留给最后一行去调整的?首先每个位之间是不影响的,全部分开。设想下面的一种构造。

    0  0  0  0  0  a1
    0  0  0  0  0  a2
    0  0  0  0  0  a3
    b1 b2 b3 b4 b5 ?
    

    最后的问号处要求a4==b6则有解,否则我们翻转任意一位都会使得那一行和那一列的异或和同时改变,最后右下角这个还是没变。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int a[105], b[105];
    
    void test_case() {
        int n, m;
        scanf("%d%d", &n, &m);
        int sumr = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            sumr ^= a[i];
        }
        int sumc = 0;
        for(int i = 1; i <= m; ++i) {
            scanf("%d", &b[i]);
            sumc ^= b[i];
        }
        if(sumr == sumc) {
            puts("YES");
            for(int i = 1; i <= n - 1; ++i) {
                for(int j = 1; j <= m - 1; ++j) {
                    printf("0 ");
                }
                printf("%d
    ", a[i]);
            }
            for(int j = 1; j <= m - 1; ++j)
                printf("%d ", b[j]);
            printf("%d
    ", sumr ^ b[m]^a[n]);
        } else
            puts("NO");
    }
    
    int main() {
    #ifdef KisekiPurin
        freopen("KisekiPurin.in", "r", stdin);
    #endif // KisekiPurin
        int t = 1;
        for(int ti = 1; ti <= t; ++ti) {
            //printf("Case #%d: ", ti);
            test_case();
        }
    }
    

    E - Rest In The Shades

    CF居然也有几何题,得做了。

    题意:x轴下方有一个移动光源平行x轴移动,x轴有一些线段。x轴上方有一些点,求每个点在阴影中的时间。

    题解:点和线段的数量太多了,暴力搞不得。但是把点和光源的起点终点连线,然后中间完整的线段部分可以直接等比例计算(中间完整的阴影的长度/交点x轴长度),然后加上两边的(假如有交)就可以了。线段已经排序且不会相交,则每个询问直接二分就可以了。

  • 相关阅读:
    Tomcat
    mybatis xml参数传递详解
    windows zookeeper集群
    @RequestParam和@RequestBody区别
    nginx学习
    先冒泡,再使用vector
    有a,b,c,d 4个球,分别出现的概率是10%,20%,30%,40%,要求编写RunDemo,每调用一次函数RunDemo,就按上面的概率出现球。
    字符串右移
    编写程序输入实现123->321
    计算机网络(一)
  • 原文地址:https://www.cnblogs.com/KisekiPurin2019/p/11904489.html
Copyright © 2020-2023  润新知