• Codeforces Round #734 (Div. 3) 【A + B1 + B2 + C + D1 + E】



    Title: Codeforces Round #734 (Div. 3)
    Date: 2021-07-25
    Tag: CF


    A. Polycarp and Coins

    题目描述:

    有一个人买东西付钱只用一元钱和二元钱, 现在他要付 n 元, 他使用一元钱的数量和二元钱数量的差值要最小, 问他付 n 元使用了多少一元钱和二元钱?

    思路:

    n % 3进行分类套路即可,余0时一元等于二元,余1时就一元钱多一张,余2时就二元钱多一张

    #include<map>
    #include<set>
    #include<stack>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<sstream>
    #include<complex>
    #include<cstring>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define endl '
    '
    #define inf 0x3f3f3f3f
    #define MAX 100000 + 50
    #define seed 13331
    #define mod 1000000007
    #define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
    #define mem(a,b) memset((a),(b),sizeof(a))
    typedef  long long ll ;
    typedef unsigned long long ull;
    //不开longlong见祖宗!
    inline int IntRead(){char ch = getchar();int s = 0, w = 1;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;}
    
    int t, n, m;
    int tr[MAX];
    
    int main(){
        cin>>t;
        while (t--) {
            cin>>n;
            int num1, num2;
            m = n % 3;
            if(m == 0){
                num1 = num2 = n / 3;
                cout<<num1<<' '<<num2<<endl;
            }
            else if(m == 1){
                num1 = n / 3 + 1;
                num2 = n / 3;
                cout<<num1<<' '<<num2<<endl;
            }
            else {
                num1 = n / 3;
                num2 = n / 3 + 1;
                cout<<num1<<' '<<num2<<endl;
            }
        }
        return 0;
    }
    

    B1. Wonderful Coloring - 1

    题目描述:

    • n个字符,要么染成红色,要么染成绿色,要么不染色

    • 相同颜色的字符俩俩不同

    • 红绿两种颜色的字符的数量相同

    问:满足以上条件,染成红色的字符的数量是多少

    思路:

    因为相同的字符要染色的话只能染红色和绿色,所以只需要记录每个字符出现的次数,分数量为1的和数量>=2的去讨论记录即可

    • 数量>=2的,红绿都可以染,就让ans += 2
    • 数量等于1的,只能染红色或绿色,就让ans += 1

    最后让ans除以2向下取整,即ans/=2

    #include<map>
    #include<set>
    #include<stack>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<sstream>
    #include<complex>
    #include<cstring>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define endl '
    '
    #define inf 0x3f3f3f3f
    #define MAX 100000 + 50
    #define seed 13331
    #define mod 1000000007
    #define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
    #define mem(a,b) memset((a),(b),sizeof(a))
    typedef  long long ll ;
    typedef unsigned long long ull;
    //不开longlong见祖宗!
    inline int IntRead(){char ch = getchar();int s = 0, w = 1;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;}
    
    ll t, n, m;
    string s;
    map<char, int>mp;
    
    int main(){
        cin>>t;
        while (t--) {
            ll ans = 0;
            mp.clear();
            cin>>s;
            for(int i = 0; i < s.size(); ++i){
                ++mp[s[i]];
            }
            n = mp.size();
            map<char, int>::iterator it = mp.begin();
            for(; it != mp.end(); ++it){
                if(it->second < 2)ans += 1;
                else ans += 2;
            }
            ans /= 2;
            cout<<ans<<endl;
        }
        return 0;
    }
    

    B2. Wonderful Coloring - 2

    题目描述:

    恶心的构造题,艹

    • n个数字,染成k种颜色,也可以不染色
    • 相同颜色的数字染色不同
    • 所有颜色的数量必须一样
    • 染色的数量尽可能多

    用0-k代表染色的颜色的种类(0代表不染色),让你构造出符合的染色方案

    思路

    首先和B1有点类似,统计每个数字出现的次数,再将所有次数>=k的搞出来,这些就是可以直接涂k种颜色的,涂就行了; 对于次数<k的集中到一起,为了防止相同数字染成一个颜色,所以就先按下标从小到达排个序,然后再算算能染几个k种,就挨个染就行了,没操作的就赋0

    这里操作起来还是比较恶心的,需要的准备的东西不少,得先用一个vector的数组存一下每个数出现的下标,便于后续操作,然后你还需要一个标记数组,对于>=k的得标记一下,便于后面从1到n循环找<k的数字的时候可以分辨出来(其实也可以不用这样,在搞>=kif下面写个else搞一下就行了),还需要一个ans数组去染色记录答案,还需要一个vector数组存<k的下标和数字,去排序啊干别的什么的

    还是比较容易超时的,建议清0的时候手动清零,别用memset,直接循环到n去清,会快很多的

    #include<map>
    #include<set>
    #include<stack>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<sstream>
    #include<complex>
    #include<cstring>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define endl '
    '
    #define inf 0x3f3f3f3f
    #define MAX 2000000 + 50
    #define seed 13331
    #define mod 1000000007
    #define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
    #define mem(a,b) memset((a),(b),sizeof(a))
    typedef  long long ll ;
    typedef unsigned long long ull;
    //不开longlong见祖宗!
    inline int IntRead(){char ch = getchar();int s = 0, w = 1;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;}
    
    int t, n, k, x;
    vector<int>tr[MAX];
    struct ran{
        int id, val;
        bool operator < (const ran &x)const{
            return val < x.val;
        }
    };
    vector<ran>v;
    
    int main(){
        scanf("%d", &t);
        while (t--) {
            scanf("%d%d", &n, &k);
            v.clear();
            for(int i = 1; i <= n; ++i)tr[i].clear();
            vector<int>vis(n + 1, 0);
            vector<int>ans(n + 1, 0);
            vector<int>ar(n + 1);
            for(int i = 1; i <= n; ++i){
                scanf("%d", &ar[i]);
                tr[ar[i]].push_back(i);
            }
            for(int i = 1; i <= n; ++i){
                if(tr[i].size() >= k){
                    for(int j = 0; j < k; ++j){
                        ans[tr[i][j]] = j + 1;
                    }
                    vis[i] = 1;
                }
            }
    //        for(int i = 1; i <= n; ++i)cout<<ans[i]<<' ';
    //        cout<<endl;
            for(int i = 1; i <= n; ++i){
                if(!vis[ar[i]]){
                    v.push_back({i, ar[i]});
                }
            }
            sort(v.begin(), v.end());
            ll num = v.size() / k * k;
            int tot = 1;
            for(int i = 0; i < num; ++i){
                ans[v[i].id] = tot++;
                if(tot == k + 1)tot = 1;
            }
            for(int i = 1; i <= n; ++i)cout<<ans[i]<<' ';
            cout<<endl;
        }
        return 0;
    }
    

    C. Interesting Story

    题目描述:

    n个只包含abcde的字符串中选出若干个字符串,使得某一个字符的出现次数大于其他四个总和,问最多可以选多少个字符

    思路:

    写五个sort去暴力莽?!

    记录每个字符串中每个字符出现的次数,枚举abcde分别作为大于其他字符总和的情况

    这里拿a做例子简单描述一下,假设每个字符串中a的数量为tr[i].a,其他的数量为tr[i].num,则我们可以计算当前这个字符串对答案的贡献是tr[i].a - (tr[i].num - tr[i].a),即tr[i].a * 2 - tr[i].num,将每个的贡献值塞到一个vector数组中去,然后从大到小排序,从头开始扫数组,用tot记录当前的贡献总值,循环的时候看当前循环到的贡献加上tot,如果 > 0说明当前的这个可以选,否则就直接退出循环

    对abcde都这样,然后取最大值即可

    #include<map>
    #include<set>
    #include<deque>
    #include<stack>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<sstream>
    #include<cstring>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define endl '
    '
    #define inf 0x3f3f3f3f
    #define MAX 200000 + 50
    #define seed 13331
    //#define mod 1000000007
    #define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
    #define mem(a,b) memset((a),(b),sizeof(a))
    typedef  long long ll ;
    typedef unsigned long long ull;
    //不开longlong见祖宗!
    inline int IntRead(){char ch = getchar();int s = 0, w = 1;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;}
    
    int t, n;
    string s;
    
    struct ran{
        int a, b, c, d, e;
        int num;
    }tr[MAX];
    
    int get_a(){
        vector<int>ans;
        for(int i = 1; i <= n; ++i){
            ans.push_back(tr[i].a * 2 - tr[i].num);
        }
        sort(ans.rbegin(), ans.rend());
        int k = 0;
        int tot = 0;
        for(int i = 0; i < n; ++i){
            if(k + ans[i] > 0){
                ++tot;
                k += ans[i];
            }
            else break;
        }
        return tot;
    }
    
    int get_b(){
        vector<int>ans;
        for(int i = 1; i <= n; ++i){
            ans.push_back(tr[i].b * 2 - tr[i].num);
        }
        sort(ans.rbegin(), ans.rend());
        int k = 0;
        int tot = 0;
        for(int i = 0; i < n; ++i){
            if(k + ans[i] > 0){
                ++tot;
                k += ans[i];
            }
            else break;
        }
        return tot;
    }
    
    int get_c(){
        vector<int>ans;
        for(int i = 1; i <= n; ++i){
            ans.push_back(tr[i].c * 2 - tr[i].num);
        }
        sort(ans.rbegin(), ans.rend());
        int k = 0;
        int tot = 0;
        for(int i = 0; i < n; ++i){
            if(k + ans[i] > 0){
                ++tot;
                k += ans[i];
            }
            else break;
        }
        return tot;
    }
    
    int get_d(){
        vector<int>ans;
        for(int i = 1; i <= n; ++i){
            ans.push_back(tr[i].d * 2 - tr[i].num);
        }
        sort(ans.rbegin(), ans.rend());
        int k = 0;
        int tot = 0;
        for(int i = 0; i < n; ++i){
            if(k + ans[i] > 0){
                ++tot;
                k += ans[i];
            }
            else break;
        }
        return tot;
    }
    
    int get_e(){
        vector<int>ans;
        for(int i = 1; i <= n; ++i){
            ans.push_back(tr[i].e * 2 - tr[i].num);
        }
        sort(ans.rbegin(), ans.rend());
        int k = 0;
        int tot = 0;
        for(int i = 0; i < n; ++i){
            if(k + ans[i] > 0){
                ++tot;
                k += ans[i];
            }
            else break;
        }
        return tot;
    }
    
    
    int main(){
        scanf("%d", &t);
        while (t--) {
            scanf("%d", &n);
            for(int i = 1; i <= n; ++i)tr[i].a = tr[i].b = tr[i].c = tr[i].d = tr[i].e = tr[i].num = 0;
            for(int i = 1; i <= n; ++i){
                cin>>s;
                tr[i].num = s.size();
                for(int j = 0; j < s.size(); ++j){
                    if(s[j] == 'a')++tr[i].a;
                    else if(s[j] == 'b')++tr[i].b;
                    else if(s[j] == 'c')++tr[i].c;
                    else if(s[j] == 'd')++tr[i].d;
                    else if(s[j] == 'e')++tr[i].e;
                }
            }
            int ans = 0;
            ans = max(ans, get_a());
            ans = max(ans, get_b());
            ans = max(ans, get_c());
            ans = max(ans, get_d());
            ans = max(ans, get_e());
            cout<<ans<<endl;       
        }
        return 0;
    }
    

    D1. Domino (easy version)

    题目描述:

    n*m为偶数的矩阵中放1 * 2(横着)和2 * 1(横着)的多米诺骨牌,现在给出k1 * 2的牌,问你能不能再放k1 * 2的情况下,用2 * 1去放满矩阵

    思路:

    首先n * m是偶数有三种情况,也就是能放tot = n * m / 2个牌

    • 对于 nm都是偶数的情况下,k必须是偶数,才能满足条件

    • 对于n是奇数时,必须先把这行放完了,剩下的就是(n-1) * m的矩阵,就变成了第一种情况,此时已经放了m/2个横着的牌,所以让k -= m/2, 能放的数量也少了m / 2个,所有让tot -= m/2

    • 对于m是奇数时,同理,必然先放 n / 2个竖着的,剩下的就是n * (m - 1)的矩阵了,和第一种情况相同,此时只有tot -= n / 2,横着的没有必须放的,就不操作k

    最后只要判断一下k的奇偶,以及tot是否合法即可

    其实看了答案就发现真的就用了个比较简单的转换思想,将二三两种情况转换成n和m都偶数的情况,再去一步判断;但是自己就是想不到,就搁那瞎讨论,分这个奇偶分那个奇偶,太艹了

    #include<map>
    #include<set>
    #include<deque>
    #include<stack>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<sstream>
    #include<cstring>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define endl '
    '
    #define inf 0x3f3f3f3f
    #define MAX 200000 + 50
    #define seed 13331
    //#define mod 1000000007
    #define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
    #define mem(a,b) memset((a),(b),sizeof(a))
    typedef  long long ll ;
    typedef unsigned long long ull;
    //不开longlong见祖宗!
    inline int IntRead(){char ch = getchar();int s = 0, w = 1;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;}
    
    int t;
    int n, m, k, p, q;
    
    int main(){
        cin>>t;
        while (t--) {
            cin>>n>>m>>k;
            q = n * m / 2;
            if(n % 2 == 1){
                k -= m / 2;
                q -= m / 2;
            }
            if(m % 2 == 1){
                q -= n / 2;
            }
            if(k < 0 || k % 2 == 1 || k > q)cout<<"NO
    ";
            else cout<<"YES
    ";
        }
        return 0;
    }
    

    D2是个构造题,就是D1的一个升级版,不仅要判断能不能按D1的要求放,还要求你用字母a到z去填充这个牌,好像还要求相邻的不能重复,好像是挺麻烦的,不到500人A了,先鸪再说(连B2都没造出来,D2能造的出来??

    E. Fixed Points

    题目描述:

    给定一个长度为n的数组a和一个常数 k

    现在有一个操作,是删除 a 数组的任意一个,使得其右边的所有的数的下标-1

    问你最少进行多少次操作能使得最终的数组 b 中至少有 k 个数的b[i] = i

    思路:

    dp

    状态:dp[i] [j] 表示前i个数中,删除 j 个数能得到的b[h] = h(1<=h<=n)的最大个数

    对于当前的ai有两种决策:

    • 删,删了aidp[i] [j]没什么影响,所以dp[i] [j] = dp[i - 1] [j - 1]
    • 不删, 就得看当前这个ai是否等于其下标了,由于他本身不删,所以删掉的 j 个就是在 i - 1之前删的,所以 ai的下标变成了 i - j,故dp[i] [j] = dp[i - 1] [j] + (a[i] == i - j)
    #include<map>
    #include<set>
    #include<deque>
    #include<stack>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<sstream>
    #include<cstring>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define endl '
    '
    #define inf 0x3f3f3f3f
    #define MAX 2000 + 50
    #define seed 13331
    //#define mod 1000000007
    #define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
    #define mem(a,b) memset((a),(b),sizeof(a))
    typedef  long long ll ;
    typedef unsigned long long ull;
    //不开longlong见祖宗!
    inline int IntRead(){char ch = getchar();int s = 0, w = 1;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;}
    
    int t;
    int n, k;
    int tr[MAX];
    int dp[MAX][MAX];
    
    int main(){
        scanf("%d", &t);
        while (t--) {
            scanf("%d%d", &n, &k);
            for(int i = 1; i <= n; ++i)scanf("%d", &tr[i]);
            for(int i = 1; i <= n; ++i){
                for(int j = 0; j <= i; ++j){
                    if(j == 0)dp[i][j] = dp[i - 1][j] + (tr[i] == i);
                    else dp[i][j] = max(dp[i - 1][j - 1], dp[i - 1][j] + (tr[i] == i - j));
                }
            }
            int ans = -1;
            for(int i = 0; i <= n; ++i){
                if(dp[n][i] >= k){
                    ans = i;
                    break;
                }
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    
    不是所有的牛奶都叫特仑苏,也不是所有的人都叫猪猪
  • 相关阅读:
    如何找出一个数组中第二大的数
    如何把一个整型数组中重复的数字去掉
    假设数组a有n个元素,元素取值范围是1~n,如何判定数组是否存在重复元素
    如何重新排列数组使得数组左边为奇数,右边为偶数,并使得空间复杂度为O(1),时间复杂度为O(n)
    给一个由n-1个整数组成的未排序的序列,其元素都是1~n中的不同的整数。如何在线性时间复杂度内寻找序列中缺失的整数
    已知大小分别为m、n的两个无序数组A、B和一个常数c,求满足A[i]+B[j]=c的所有A[i]和B[j]
    如何找出数组中符合条件的数对
    如何找出数组中出现奇数次的元素
    云服务器ECS挖矿木马病毒处理和解决方案
    Java下载https文件上传到阿里云oss服务器
  • 原文地址:https://www.cnblogs.com/chelsea0901/p/15059469.html
Copyright © 2020-2023  润新知