首页 > 其他分享 >AtCoder Beginner Contest 346

AtCoder Beginner Contest 346

时间:2024-04-14 18:33:05浏览次数:32  
标签:AtCoder Beginner int ap 346 num 字符串 size define




B - Piano

难度: ⭐⭐

题目大意

现有S为无限重复字符串"wbwbwwbwbwbw"形成的字符串。请问S中是否存在由W次出现的'w'和B次出现的'b'组成的子字符串T;

解题思路

字符串T显然可以由S的一段后缀 + 若干个S + S的一段前缀组成; 但是, 这个题的W和B都最大为100; 也就是说, 如果存在, 那么一定会在S重复200次以内的时候得到, 所以暴力就可以了;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, res = inf;
string s = " wbwbwwbwbwbw";
string s1;
signed main(){
    IOS;
    cin >> w >> b;
	for (int i = 0; i <= 20; i++) {
		for (int j = 0; j < (int)s.length(); j++) {
			s1.push_back(s[j]);
		}
	}
	for (int i = 0; i < (int)s1.size(); i++) {
		int cntw = 0, cntb = 0;
		for (int j = i; j < (int)s1.size(); j++) {
			if (w == cntw && b == cntb) {
				cout << "Yes\n";
				return 0;
			}
			if (s1[j] == 'b') cntb++;
			else cntw++;
		}
	}
	cout << "No";
	return 0;
}




C -

难度: ⭐⭐

题目大意

现有一个长度为n的序列A, 给定一个正整数k, 请问1 - k中未出现在序列A中的数字之和;

解题思路

反向思路, 我们可以先求1 - k中出现在序列A中的数字之和; 对此先把序列A中小于等于k的部分进行排序去重求和; 最后用k * (k + 1) / 2减去它就可以了;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, res = inf;
int p[N], s[N];
vector<int> v;
signed main(){
    IOS;
    cin >> n >> m;
	v.push_back(0);
	for(int i = 0; i < n; i++){
		int a;
		cin >> a;
		v.push_back(a);
	}
	sort(v.begin(), v.end());
	v.erase(unique(v.begin() , v.end()), v.end());
	for(int i = 1; i < v.size(); i++){
		s[i] = s[i - 1] + v[i];
	}
	int l = upper_bound(v.begin(), v.end(), m) - v.begin();
	int x = m * (m + 1) / 2;
	x -= s[l - 1];
	cout << x;
	return 0;
}




D - Gomamayo Sequence

难度: ⭐⭐⭐

题目大意

对于一个长度为n的01字符串S, 只有S中只有一处相邻的两个数字相同的时候才是一个好字符串, eg 0100101; 并且对于1 ~ n的字符S[i], 我们可以花费C[i]将其反转, 0变成1, 1变成0; 请问把字符串S变成一个好字符串的最小代价是多少;

解题思路

可以用dp来解决, dp1[i][j]表示得到长度为i且情况为j的好字符串的最小代价; dp2[i][j]表示得到长度为i且情况为j的坏字符串的最小代价; 这里的坏字符串表示01交替的字符串, eg: 01010101; 情况j意思是, 如果j为1, 则说明第i个和第i - 1个字符不同, j为0则为相同;
这样我们就可以根据S[i]和S[i - 1]来进行状态转移; 具体转移方程可以看代码;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, res = inf;
int dp1[N][2], dp2[N][2], p[N];
string s;
signed main(){
    IOS;
	string s;
	cin >> n >> s;
	s = ' ' + s;
	for(int i = 1; i <= n; i++){
		cin >> p[i];
	}
	dp2[1][1] = p[1];
	dp1[1][1] = dp1[1][0] = inf;
	for(int i = 2; i <= n; i++){
		if(s[i] == s[i - 1]){
			dp1[i][0] = min(dp2[i - 1][0], dp1[i - 1][1]);
			dp1[i][1] = min(dp2[i - 1][1], dp1[i - 1][0]) + p[i];

			dp2[i][0] = dp2[i - 1][1];
			dp2[i][1] = dp2[i - 1][0] + p[i];
		}
		else{
			dp1[i][0] = min(dp2[i - 1][1], dp1[i - 1][0]);
			dp1[i][1] = min(dp2[i - 1][0], dp1[i - 1][1]) + p[i];

			dp2[i][0] = dp2[i - 1][0];
			dp2[i][1] = dp2[i - 1][1] + p[i];
		}
	}
	cout << min(dp1[n][1], dp1[n][0]);
	return 0;
}




E - Paint

难度: ⭐⭐⭐

题目大意

现有一个n x m网格, 初始均为0; 现在进行m次操作(a, b, c), 如果a为1, 则把第b行都变成数字c, 如果a为2, 则把第b列都变成数字c; 最后输出网格中有多少种颜色, 每个颜色都有多少个格子;

解题思路

因为后操作会把之前的操作覆盖, 所以我们可以倒着处理, 每次处理完一个操作后更新当前还可以染色的长和宽即可;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int dx[] = {1, 0, -1, 0, 1, 1, -1, -1};
int dy[] = {0, 1, 0, -1, 1, -1, 1, -1};
int n, m, k;
struct node{
    int a, b, c;
};
node p[N];
bool row[N], col[N];
map<int, int> mp;
signed main(){
    IOS;
    int sum = 0;
    cin >> n >> m >> k;
    for(int i = 1; i <= k; i++){
        int a, b, c;
        cin >> a >> b >> c;
        p[i] = {a, b, c};
    }
    mp[0] = n * m;
    for(int i = k; i >= 1; i--){
        if(p[i].a == 1){
            if(row[p[i].b] || m == 0) continue;
            mp[p[i].c] += m;
            sum += m;
            n--;
            row[p[i].b] = true;
        }
        else{
            if(col[p[i].b] || n == 0) continue;
            mp[p[i].c] += n;
            sum += n;
            m--;
            col[p[i].b] = true;
        }
    }
    mp[0] -= sum;
    if(mp[0] == 0) mp.erase(0);
    cout << mp.size() << endl;
    for(auto t : mp){
        cout << t.first << ' ' << t.second << endl;
    }
	return 0;
}




F - SSttrriinngg in StringString

难度: ⭐⭐⭐⭐

题目大意

对于一个长度为n的字符串S, 函数f(S, k)表示把S重复k次后得到的字符串, g(S, k)表示把S中的每个字符都重复k次后得到的字符串; ed: S = "abc", 那么f(S, 2) = "abcabc", g(S, 3)= "aaabbbccc"; 当然, f(S, 0)和g(S, 0)都是空字符串; 给你一个正整数N和字符串S, T; 求最大的非负整数k,使得g(T, k)是f(S, N)的子序列; 注意,根据定义,g(T, 0)总是f(S, N)的子序列。

解题思路

为了方便, 我们开始两个数组p[N][26], f[N][26]; p[i][j] = x表示S的前i个字符中字母j的个数, f[i][j] = x表示S的前x个字符中恰好有i个字母j, 并且x尽可能小; 因为k有单调性, 所以可以用二分来求;
在check函数中, 先设定两个指标num和pos代表当前进度, 表示已经经过了num个字符S, 并且此时正位于第num + 1个S的pos位置; 我们遍历字符串T, 对于T[i], 我们需要在当前进度的基础上往后找N个字符T[i], 而且是从S的一段后缀 + 若干个S + S的一段前缀中找; 中间的若干个S可以对p[S.size() - 1][T[i]]取余来得到; 接下来就可以分类讨论, 先看从pos到最后中T[i]的数量够不够用, 如果不够用就num + 1, pos = 0, 再从前缀开始找;
注意这里有个坑点, 如果N对p[S.size() - 1][T[i]]取余为0, 那么不能直接加上N / p[S.size() - 1][T[i]], 而是加上(N / p[S.size() - 1][T[i]]) - 1, 然后再从后缀前缀中再找p[S.size() - 1][T[i]]个T[i], 这样才能把空间利用最大化;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int dx[] = {1, 0, -1, 0, 1, 1, -1, -1};
int dy[] = {0, 1, 0, -1, 1, -1, 1, -1};
int n, m, res;
string s, t;
int p[N][26], f[N][26];
bool check(int u){
    if(u == 0) return true;
    int num = 0;
    int pos = 0;
    for(int i = 1; i < t.size(); i++){
        int ap = t[i] - 'a';
        if(p[s.size() - 1][ap] == 0) return false;
        int a = u / p[s.size() - 1][ap];
        int b = u % p[s.size() - 1][ap];
        if(b == 0){
            num += a - 1;
            b = p[s.size() - 1][ap];
        }
        else num += a; 
        int re = p[s.size() - 1][ap] - p[pos][ap];
        if(re >= b){
            pos = f[b + p[pos][ap]][ap];
        }
        else{
            num++;
            pos = f[b + p[pos][ap] - p[s.size() - 1][ap]][ap];
        }
        if(num > n || (num == n && pos > 0)){
            return false;
        }
    }
    return true;
}
signed main(){
    IOS;
    cin >> n >> s >> t;
    s = ' ' + s;
    t = ' ' + t;
    for(int i = 0; i < 26; i++){
        for(int j = 1; j < s.size(); j++){
            if(s[j] == 'a' + i){
                p[j][i] = p[j - 1][i] + 1;
            }
            else p[j][i] = p[j - 1][i];
        }
    }
    for(int i = 1; i < s.size(); i++){
        int num = p[i][s[i] - 'a'];
        f[num][s[i] - 'a'] = i;
    }
    int l = 0, r = inf;
    while(l < r){
        int mid = l + r + 1 >> 1;
        if(check(mid)){
            l = mid;
        }
        else r = mid - 1;
    }
    cout << l;
	return 0;
}

标签:AtCoder,Beginner,int,ap,346,num,字符串,size,define
From: https://www.cnblogs.com/mostimali/p/18134505

相关文章

  • [ABC349] AtCoder Beginner Contest 349 题解
    [ABC349]AtCoderBeginnerContest349题解目录[ABC349]AtCoderBeginnerContest349题解A-ZeroSumGameB-CommencementC-AirportCodeD-DivideIntervalE-WeightedTic-Tac-ToeF-SubsequenceLCMG-PalindromeConstruction总结A-ZeroSumGame零和博弈,......
  • AtCoder Beginner Contest 349
    B-Commencement难度:⭐题目大意给定一个字符串,问这个字符串中出现的字母是否都恰好为0个或者2个;解题思路数据很小,暴力就行;神秘代码#include<bits/stdc++.h>#defineintlonglong#defineIOSios::sync_with_stdio(false);cin.tie(0);cout.tie(0);#def......
  • AtCoder Beginner Contest 349
    A-ZeroSumGame(abc349A)题目大意\(n\)个人游戏,每局有一人\(+1\)分,有一人\(-1\)分。给定最后前\(n-1\)个人的分数,问第\(n\)个人的分数。解题思路零和游戏,所有人总分是\(0\),因此最后一个人的分数就是前\(n-1\)个人的分数和的相反数。神奇的代码n=input()prin......
  • AtCoder Beginner Contest 347
    A-Divisible#include<bits/stdc++.h>usingnamespacestd;usingi32=int32_t;usingi64=longlong;#defineinti64usingvi=vector<i64>;usingpii=pair<int,int>;usingpiii=tuple<int,int,int>;constintinf=1e......
  • atcoder beginer 347 (abc347) D E 题解
     D就是二进制下,哪些位置有重合(两个1),哪些位置没有重合(1个1,1个0),剩下的都是0。xor的结果<2^60,就是小于60位(二进制下)。注意要有要求两个数需要是2^60,于是要有大小的判断,因为有的a,b会2^60,但是按照题目要求,这个情况不行。比如xor的结果,60位都是1,然后a、b各有60个1,那么需要有30个1......
  • atcoder beginer 348 (abc348) D E F 题解
     E非常经典的树上操作(树上DP)。父节点到某个子节点,值是如何变化的。1#include<cstdio>2#include<cstdlib>3#include<cstring>4#include<cmath>5#include<cstdbool>6#include<string>7#include<algorithm>8#include<iost......
  • AtCoder Beginner Contest 348
    B-FarthestPoint难度:⭐题目大意一个坐标系有x个点,对于每个点找出距离其最远的点;解题思路数据很小,暴力就行;神秘代码#include<bits/stdc++.h>#defineintlonglong#defineIOSios::sync_with_stdio(false);cin.tie(0);cout.tie(0);#defineendl'\n'......
  • [ABC348] Atcoder ABC 248 A~G 题解
    [ABC348]AtcoderABC248A~G题解A模拟B模拟,不卡精度。C模拟D注意,药不可以拿着,只可以在那个格子吃掉。这就意味着,我们无论何时到达某个点,到达的点的集合都是固定的。所以对于每个药店跑BFS,然后看起点到终点是否连通即可。intn,m,k,ad[N][N],f[N][N],in[N][N],......
  • AtCoder Beginner Contest 348 A-F 题解
    A-PenaltyKickQuestion高桥将在一场足球比赛中获得\(N\)个点球。对于第\(i\)个罚球,如果\(i\)是\(3\)的倍数,他将罚球失败,否则罚球成功。请打印他罚球的结果。Solution当\(i\%3==0\)时说明能被\(3\)整除Code#include<bits/stdc++.h>usingnamespacest......
  • AtCoder Beginner Contest 348
    地址。赛时情况A、B题都很显然,C题大概推了好一会儿,最后还是做出来了。D题感觉十分难做,估计很难写,看了E。感觉还是不会,听说是原题,搜了一下,发现是树的重心,我还不会。直接贺题解,发现不对。修改了一下还是不对,最后发现INF取小了,过了。后面的不看了。赛后总结还行,跳过D......