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 ‘\n‘
#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 ‘\n‘
#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 ‘\n‘
#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 ‘\n‘
#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 ‘\n‘
#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\n";
        else cout<<"YES\n";
    }
    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 ‘\n‘
#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;
}

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

上一篇:oracle中imp命令具体解释


下一篇:一千行MySQL学习笔记