AtCoder Beginner Contest 404

学习记录


原题位置:https://atcoder.jp/contests/abc404

A Not Found 2 sec 1024 MB Submit

题目:将字符串的字符用数组存储,出现则计次,最后输出计次为0的字符即可

#include<bits/stdc++.h>
using namespace std;

int main(){

    string s;
    cin >> s;
    vector<int> v(27 , 0);
    for(auto i : s){
        v[i - 'a']++;
    }
    for(int i = 0; i <= 27;i ++){
        if(v[i] == 0){
            printf("%c" , i + 'a');
            return 0;
        }
    }
}

B Grid Rotation 2 sec 1024 MB Submit

题目给的是两张二维网格s 和 t ,每个网格都有颜色,为白色或者黑色,要求是通过不限次数的 将s表整体顺时针旋转90度 和 将网格颜色反转 这两个操作来把 s 表变成 t 表,要求次数尽可能少
解题:操作:要么旋转,要么改色, 那就有三种搭配,
· 多次旋转 多次改色 11122222
· 多次改色 多次旋转 22211111
· 改色 和 旋转 混搭 12121212121221
显而易见,3 排除, 混搭变数很多, 那么分类计算旋转不同角度后的改色次数,最少的就是答案
将数据读入二维数组 s 和 t 中,再对比旋转后的s表和t表,计次,最后输出最小值
由于旋转操作也算入计次,所以代码中的cnt表有初始值

#include<bits/stdc++.h>
using namespace std;

int main(){

    int N;
    cin >> N;
    //s t 表
    vector<vector<char>> s(N + 1 , vector<char>(N + 1)) , t(N + 1 , vector<char>(N + 1));
    //这里使用cnt数组来存储不同旋转角度的改色次数
    vector<int> cnt = {0 , 1 , 2 , 3};
    for(int i = 1;i <= N;i++){
        for(int j = 1;j <= N;j++){
            cin >> s[i][j];
        }
    }
    for(int i = 1;i <= N;i++){
        for(int j = 1;j <= N;j++){
            cin >> t[i][j];
        }
    }
    //不旋转
    for(int i = 1;i <= N;i++){
        for(int j = 1;j <= N;j++){
            if(s[i][j] != t[i][j]){
                cnt[0]++;
            }
            // cout << s[i][j];
        }
        // cout << endl;
    }
    //90
    for(int i = 1;i <= N;i++){
        for(int j = N , k = 1;j >= 1 , k <= N;j-- , k++){
            if(s[j][i] != t[i][k]){
                cnt[1]++;
            }
            // cout << s[j][i];
        }
        // cout << endl;
    }
    //180
    for(int i = N , k = 1;i >= 1 , k <= N;i-- , k++){
        for(int j = N , m = 1;j >= 1 , m <= N;j-- , m++){
            if(s[i][j] != t[k][m]){
                cnt[2]++;
            }
        }
    }
    //270
    for(int i = N , k = 1;i >= 1 , k <= N;i-- , k++){
        for(int j = 1;j <= N;j++){
            if(s[j][i] != t[k][j]){
                cnt[3]++;
            }
        }
    }
    cout << *min_element(cnt.begin() , cnt.end());
    return 0;
}

C Cycle Graph? 2 sec 1024 MB Submit

这题的话,给了一张图的信息,判断图是否是循环图,循环图点和边数量相同,并且每个点的度数为2,循环图必然是连通的,所以dfs或者bfs走一遍,那么每个点和边都可以走到,稠密图用bfs,稀疏图用dfs,再看N和M的范围,所以选择bfs解题

#include<bits/stdc++.h>
using namespace std;

int main(){
	int n , m;
	cin >> n >> m;
	
	if(n != m){
		cout << "No" << endl;
		return 0; 
	}
	
	vector<vector<int>> vv(n);
	vector<int> cnt(n , 0);
	
	for(int i = 1;i <= m;i++){
		int x , y;
		cin >> x >> y;
		x--;
		y--;
		vv[x].push_back(y);
		vv[y].push_back(x);
		cnt[x]++;
		cnt[y]++;
	} 
	for(int i : cnt){
		if(i != 2){
			cout << "No" << endl;
			return 0; 
		}
	}
	vector<bool> vst(n , false);
	queue<int> q;
	q.push(0);
	vst[0] = true;
	int cnt2 = 1;
	while(!q.empty()){
		int u = q.front();
		q.pop();
		for(int v : vv[u]){
			if(!vst[v]){
				vst[v] = true;
				q.push(v);
				cnt2++;
			}
		}
	}
	
	if(cnt2 == n){
		cout << "Yes" << endl;
	}else{
		cout << "No" << endl;
	}
	return 0;
}

D Goin’ to the Zoo 2 sec 1024 MB Submit

题意:给了N个动物园,又给了M个想看的动物,后面的数据是告诉我们每只想看的动物在哪些动物园里面可以看,例如下面给的样例:
4 3
1000 300 700 200
3 1 3 4
3 1 2 4
2 1 3
这里面的3 1 3 4是第一行,所以这第一行的数据表示M个想看的动物里面的第一个想看的动物的数据,是有3个动物园可以看到,分别是 1号,3号,4号动物园;
解题:N最大为10,每一种动物园有三种去法,为0 , 1 ,2次,多于2次就是浪费钱了,暴力枚举的时间复杂度计算大约为O(3^N ),尝试暴力枚举解题;
代码思路:
先获取数据,将数据存储好,对于jz[]数组,是进制,里面存的是3的每个次方的数据,方便后面使用;
对于主要遍历部分,思路:从0开始,一直到3^N,所有的可能都走一遍,创建一个amlcnt数组,里面是每个动物被访问次数的记录,仅仅用于本次循环,因为后面判断每个动物是否被访问两次,true才算成功,最后与上一次循环得出的费用比较,取低的值。
for(int i = 1;i <= N;i++){
int tm = cnt / jz[i - 1] % 3;
这段代码的意思是对于每个动物园,我们都把他看成一个数数,然后这个数一个三进制,int tm = cnt / jz[i - 1] % 3;是用于求每个三进制对应的值,所以主要思想是将遍历看成三进制数字,这是一种位运算思想,因为每个动物园只能去三次,所以可以看成三进制,再进行遍历,这样子的遍历是每次都有的,不会漏,就像从1数到100,每个数字都会数到,只不过这里是三进制的数数,从0数到3^N,每次数数的时候都计算一次费用。

#include<bits/stdc++.h>
using namespace std;

int main(){
	ios::sync_with_stdio(0) , cin.tie(0);
//	freopen("cpptest.txt" , "r" , stdin);
	int N , M;
	cin >> N >> M;
	
	vector<int> cost(N+1);
	for(int i = 1;i <= N;i++){
		cin >> cost[i];
	} 
	
	vector<int> jz(N + 1);
	jz[0] = 1;
	for(int i = 1;i <= N;i++){
		jz[i] = pow(3 , i);
	}
	
	vector<vector<int>> zoo(N+1);
	for(int i = 1;i <= M;i++){
		int t; cin >> t;
		for(int j = 0;j < t;j ++){
			int x; cin >> x;
			zoo[x].push_back(i);
		}
	}
 	long long ret = 1e18;
 	for(int cnt = 0;cnt < jz[N];cnt++){
		vector<int> amlcnt(M + 1 , 0);
		long long tcost = 0;
		for(int i = 1;i <= N;i++){
			int tm = cnt / jz[i - 1] % 3;
			tcost += tm * cost[i];
			for(int j = 0;j < tm;j++){
				for(int taml: zoo[i]){
					amlcnt[taml]++;
				}
			}
		}
		bool tbl = true;
		for(int i = 1;i <= M;i++){
			if(amlcnt[i] < 2){
				tbl = false;
				break;
			}
		}
		if(tbl == true){
			ret = min(tcost , ret);
		}
	}
	cout << ret << endl;
		 
	return 0;
}

G Specified Range Sums 2 sec 1024 MB Submit

题意:给了三个正整数序列,需要我们求一个A序列,这个A序列如果不存在则输出-1,A序列满足下面的要求:

在这里插入图片描述

题目中的N是对序列的长度要求,M是给出的三个序列的长度,上面的这个公式解释:
我们看样例1:
5 3
1 2 4
2 3 5
5 5 5
那么L:1 2 5
R:2 3 5
M:4 5 5
对于范围内的i,代入求和公式,
当i = 1时,L1 = 1 , R1 = 2,所以区间为【1,2】那么Aj = A1 + A2 = S1 = 4
当i = 2时,L2 = 2 , R2 = 3,所以区间为【2,3】那么Aj = A2 + A3 = S2 = 5
当i = 3时,L3 = 5 , R3 = 5,所以区间为【5,5】那么Aj = A5 = 5
所以我们可以求A1 , A2 , A3 ,A5,题目要去A序列有5个,并且A序列求和要偏小,而序列都是正整数序列,所以我们A4给1作为他的值。
A1 + A2 = 4
A2 + A3 = 5
A5 = 5
那么有下面几种可能:
A1 A2 A3 A4 A5
1 3 2 1 5
2 2 3 1 5
3 1 4 1 5
求和下来,最上面的那个种和最小,为12,所以答案为12,
所以这道题目就变成了对一组不等式求解的问题,我们可以使用差分约束系统,那么就成了一道差分约束的模板题

#include<bits/stdc++.h>
using namespace std;

struct Edge {
    int from, to;
    long long w;
};

bool bellmanFord(int n, const vector<Edge>& e, vector<long long>& d) {
    d.assign(n + 1, LLONG_MAX);
    d[0] = 0;
    for (int i = 0; i < n; ++i) {
        for (const Edge& edge : e) {
            if (d[edge.from] != LLONG_MAX && d[edge.from] + edge.w < d[edge.to]) {
                d[edge.to] = d[edge.from] + edge.w;
            }
        }
    }
    for (const Edge& edge : e) {
        if (d[edge.from] != LLONG_MAX && d[edge.from] + edge.w < d[edge.to]) {
            return false;
        }
    }
    return true;
}

int main() {
    int n, m;
    cin >> n >> m;

    vector<Edge> e;

    for (int i = 0;i < m;i++) {
        int l, r;
        long long s;
        cin >> l >> r >> s;
        e.push_back({l - 1, r, -s});
        e.push_back({r, l - 1, s});
    }

    for (int j = 1; j <= n; ++j) {
        e.push_back({j - 1, j, -1});
    }

    vector<long long> d;
    if (!bellmanFord(n, e, d)) {
        cout << -1 << endl;
    } else {
        cout << -d[n] << endl;
    }
    return 0;
}    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值