• Codeforces Round #662 (Div. 2)


    A. Rainbow Dash, Fluttershy and Chess Coloring (CF 1393 A)

    题目大意

    给定一个(n imes n)的棋盘,要黑白间隔涂色。每次只能选择一些格子涂色,这些格子必须与某些已经涂色的格子相邻,问最小涂色次数。初始时最外围的一圈都可以涂色。

    解题思路

    开始看样例有种输出n-1的冲动

    想象一下涂色情况可知,第一次涂最外围一圈的白色,第二次涂最外围的黑色和第二外围的黑色,第三次涂第二外围的白色和第三外围的白色……

    若n是偶数,则最后是涂一个四个格子的两个颜色,然后还要一次涂另一个颜色,次数是(dfrac{n}{2} + 1)

    若n是奇数,最后一次则是涂一个格子,次数是(lfloor dfrac{n}{2} floor + 1)

    综上,答案就是(dfrac{n}{2} + 1)(整除)。

    神奇的代码
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    int main(void) {
        ios::sync_with_stdio(false); 
        cin.tie(0); 
        cout.tie(0);
        int kase; cin>>kase;
        for (int ii = 1; ii <= kase; ii++) {
            int n;
            cin>>n;
            cout<<(n/2+1)<<endl;
        }
        return 0;
    }
    


    B. Applejack and Storages (CF 1393 B)

    题目大意

    初始有(n)块木板,并已知每块木板的长度。现有(q)次操作,每次操作会增加或者移除已有的长度为x的木板,问,每次操作后,是否能从这些木板中选出一些木板来,作出一个矩形和一个正方形。(正方形也是特殊的矩形)

    解题思路

    统计一下同一长度4个4个的有多少份,2个2个的有多少份,判断就可以了。

    神奇的代码
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    const int N = 1e5+8;
    
    int n,q,l;
    
    int cnt[N];
    
    multiset<int> two,four;
    
    char s[5];
    
    int main(void) {
        read(n);
        for(int u,i = 1; i <= n; ++ i){
            read(u);
            if (cnt[u] % 4 == 3){
                four.insert(u);
            }
            if (cnt[u] % 2 == 1){
                two.insert(u);
            }
            cnt[u]++;
        }
        read(q);
        while(q--){
            scanf("%s",s);
            read(l);
            if (s[0] == '+'){
                if (cnt[l] % 4 == 3){
                    four.insert(l);
                }
                if (cnt[l] % 2 == 1){
                    two.insert(l);
                }
                cnt[l]++;
            }else{
                if (cnt[l] % 4 == 0){
                    four.erase(four.find(l));
                }
                if (cnt[l] % 2 == 0){
                    two.erase(two.find(l));
                }
                cnt[l]--;
            }
            if (four.size() >= 2) puts("YES");
            else if (four.size() == 0) puts("NO");
            else if (two.size() >=4) puts("YES");
            else puts("NO");
        }
        return 0;
    }
    


    C. Pinkie Pie Eats Patty-cakes (CF 1393 C)

    题目大意

    给定(n)个数字,要求重新排列这n个数字,使得同一个数字之间的距离的最小值最大。两个相同数的距离即这两个数之间的数字个数。

    解题思路

    很显然出现次数最多的数字是决定答案的关键。设数字中出现最多的次数为ma次,我们将这ma个数字作为隔板,隔板之间能够放的最多的数字即为(frac{n - ma}{ma - 1}),至于余数可以放到最后一个隔板的右边,总存在一种方式,其他数字的最小距离不会大于隔板间的数量。

    但如果出现次数为ma次的数字不止一个,而是有cnt个,我们就可以把这cnt个捆绑在一起,即一个长度为cnt的隔板。

    所以最终答案即为(dfrac{n - ma * cnt}{ma - 1} + cnt - 1)

    神奇的代码
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    int main(void) {
        int kase; read(kase);
        for (int ii = 1; ii <= kase; ii++) {
            int n;
            read(n);
            vector<int> tot(n+1);
            int ma = 0;
            int cnt = 0;
            for(int a, i = 1; i <= n; ++ i){
                read(a);
                tot[a]++;
                if (ma < tot[a]){
                    ma = tot[a];
                    cnt = 1;
                }else if (ma == tot[a])
                    ++cnt;
            }
            int ans = (n - ma * cnt) / (ma - 1) + cnt - 1;
            write(ans,'
    ');
        }
        return 0;
    }
    


    D. Rarity and New Dress (CF 1393 D)

    题目大意

    给定一张网格图,问由相同字母组成的菱形个数有多少。一个格子也算是一个菱形。

    解题思路

    一个菱形有一个所谓的中心,从数据范围来看我们自然不能从中心BFS来得到它能拓展多少。

    我们把菱形拆成中心所在的一条线,上三角形和下三角形。

    我们设(up[i][j])表示以((i,j))为中心的上三角形的长度(值为左或右拓展的距离),(down[i][j])为下三角形,(l[i][j])为从((i,j))向左拓展的距离,(r[i][j])为向右拓展的距离,则((i,j))点所形成的最大菱形即为(min(up[i][j],down[i][j]))

    转移

    (up[i][j] = min(up[i-1][j], min(l[i][j], r[i][j]))

    (down[i][j] = min(down[i+1][j], min(l[i][j], r[i][j]))

    还有一个不太理解的,是设(dp[i][j])表示以((i,j))为底部点,最大拓展的长度。(1,1)是左上角。

    而对于以((i,j))为底部点的菱形,可以看做是以((i-1,j))为底部点的菱形往下边拓展一格,或者以((i-1,j-1))为底部点的菱形往右边拓展一格,或者以((i-1,j+1))为底部点的菱形往左边拓展一格。由于往右边或往右边拓展一格时,顶部的格子会往上拓展一个,此时又有((i-2,j))的限制?

    至于会取(dp[i][j] = min(dp[i-1][j],dp[i-2][j],dp[i-1][j-1],dp[i-1][j+1]) + 1),如果((i,j),(i-1,j),(i-1,j-1),(i-1,j+1),(i-2,j))字母相同的话,否则(dp[i][j] = 1)

    神奇的代码
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    const int N = 2e3+8;
    
    char s[N][N];
    
    LL up[N][N],down[N][N],l[N][N],r[N][N];
    
    LL ans;
    
    int n,m;
    
    int main(void) {
        read(n);
        read(m);
        for(int i = 0; i < n; ++ i){
            scanf("%s",s[i]);
        }
        for(int i = 0; i < n; ++ i){
            for(int sign=0,cnt=1,j = 0; j < m; ++ j){
                if (s[i][j] != sign){
                    sign = s[i][j];
                    cnt = 0;
                }
                ++cnt;
                l[i][j] = cnt;
                up[i][j] = down[i][j] = 1;
            }
            for(int sign=0,cnt=1,j = m-1; j >= 0; -- j){
                if (s[i][j] != sign){
                    sign = s[i][j];
                    cnt = 0;
                }
                ++cnt;
                r[i][j] = cnt;
            }
        }
        for(int i = 1; i < n; ++ i){
            for(int j = 0; j < m; ++ j){
                if (s[i][j] == s[i-1][j]){
                    up[i][j] = min(up[i-1][j] + 1, min(l[i][j], r[i][j]));
                }
            }
        }
        for(int i = n-1; i >= 0; -- i){
            for(int j = 0; j < m; ++ j){
                if (s[i][j] == s[i+1][j]){
                    down[i][j] = min(down[i+1][j] + 1, min(l[i][j], r[i][j]));
                }
            }
        }
        for(int i = 0; i < n; ++ i)
            for(int j = 0; j < m; ++ j)
                ans += min(up[i][j],down[i][j]);
        write(ans,'
    ');
        return 0;
    }
    


  • 相关阅读:
    微信小程序音频播放
    jsonp跨域请求-最简单的方法
    mysql explain 正常,但是实际上是全盘扫描
    lnmp运行过程中出现502处理方法
    [Python]利用type()动态创建类
    Django-form表单
    Django-认证系统
    Django-model基础
    Django-MTV
    前端基础之:JQuery(可编辑版)
  • 原文地址:https://www.cnblogs.com/Lanly/p/13460553.html
Copyright © 2020-2023  润新知