Loading

AtCoder Beginner Contest 307




B - racecar

题目大意

给定n个字符串, 问能不能从中找出两个字符串拼成一个回文串

解题思路

数据不大, 暴力即可;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 5000;
int n, m, k, idx;
vector<string> v;
bool check(string s1,string s2) {
	string s = s1 + s2;
	for (int i = 0, j = s.size() - 1; i < j; i++, j--) {
		if (s[i] != s[j]) return false;
	}
	return true;
}
signed main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		string s;
		cin >> s;
		v.push_back(s);
	}
	for (int i = 0; i < v.size(); i++) {
		for (int j = i + 1; j < v.size(); j++) {
			if (check(v[i], v[j])||check(v[j],v[i])) {
				cout << "Yes" << endl;
				return 0;
			}
		}
	}
	cout << "No" << endl;
	return 0;
}




C - Ideal Sheet

题目大意

给定两个图A B, 它们都是由黑色快和透明色块组成的; 现在给出无限大的平面和一个图C, 要求用A和B在平面上拼成C, A和B都只能用一次且可以重叠, 不能剪裁不能旋转, 但是在平面的位置可以随意选择; 注意A和B必须全部用上, 不能只用A不用B;

解题思路

这个题我是真不想写...光是读题就读了好久, 思路不难但是很复杂...;
因为A和B不能旋转和剪裁, 所以我们只要知道一个黑色快的位置, 就能知道其他所有黑色快的位置; 所以我们先取出A和B中的一个点作为参照点; 这个题数据很小, 直接考虑暴力; 我们可以找到C中一个黑色块的位置作为C的参照点, 把A的参照点放在C的参照点上, 然后再遍历C中除了参照点以外的黑色快的位置, 然后算出这个点和C的参照点之间的相对位置, 然后用A的参照点加上这个相对位置, 看看A中有没有黑色快在这个位置上 ( 可以用map存A中黑色块位置 ) , 如果有则标记一下C中这个点的位置 ( 注意是要标记C中的位置, 不要记成A中的 ) , 没有则只能留给B了; 每找完一个C个参照点我们都要算一下 C中有多少个标记的点, 如果数量小于A中黑色块的数量, 那肯定是不符合要求; 如果符合要求就继续再看B, 过程是一样的, 区别只是每次找完C的参照点之后就要看看当前的标记能不能满足题目要求;
因为A和B可以在平面上随意移动, 所以黑色块在A和B上的坐标是没有意义的, 只能用相对位置的坐标;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N =15;
int n, m, k, idx;
map<PII, int> mp1;
map<PII, int> mp2;
map<PII, int> mp3;
vector<PII> v1;
vector<PII> v2;
vector<PII> v3;
bool st1[N][N];
bool st2[N][N];
signed main() {
	idx = 3;
	while (idx--) {
		cin >> n >> m;
		for (int i = 1; i <= n; i++) {
			string s;
			cin >> s;
			for (int j = 0; j < m; j++) {
				if (s[j] == '#') {
					if (idx == 0) {
						v3.push_back({ i,j+1 });
						mp3[{i, j+1}] = 1;
					}
					else if (idx == 1) {
						v2.push_back({ i,j+1 });
						mp2[{i, j+1}] = 1;
					}
					else if (idx == 2) {
						v1.push_back({ i,j+1 });
						mp1[{i, j+1}] = 1;
					}
				}
			}
		}
	}
	int ax = v1[0].first, ay = v1[0].second;
	int bx = v2[0].first, by = v2[0].second;
	for (int i = 0; i < v3.size(); i++) {
		bool f = true;
		memset(st1, false, sizeof st1);
		int cx = v3[i].first, cy = v3[i].second;
		st1[cx][cy] = true;
		int num1 = 1;
		for (int j = 0; j < v3.size(); j++) {
			if (j == i) continue;
			int dx = v3[j].first - cx, dy = v3[j].second - cy;
			if (mp1[{ax + dx, ay + dy}]) {
				st1[v3[j].first][v3[j].second] = true;
				num1++;
			}
		}
		if (num1 < v1.size()) continue;
		for (int k = 0; k < v3.size(); k++) {
			bool f = true;
			memset(st2, false, sizeof st2);
			int cx2 = v3[k].first, cy2 = v3[k].second;
			st2[cx2][cy2] = true;
			int num2 = 1;
			for (int j = 0; j < v3.size(); j++) {
				if (j == k) continue;
				int dx = v3[j].first - cx2, dy = v3[j].second - cy2;
				if (mp2[{bx + dx, by + dy}]) {
					st2[v3[j].first][v3[j].second] = true;
					num2++;
				}
			}
			if (num2 < v2.size()) continue;
			for (auto t : mp3) {
				int a = t.first.first, b = t.first.second;
				if ((!st1[a][b])&&(!st2[a][b])) {
					f = false;
					break;
				}
			}
			if (f) {
				cout << "Yes" << endl;
				return 0;
			}
		}
	}
	cout << "No" << endl;
	return 0;
}




D - Mismatched Parentheses

题目大意

给定一个字符串, 将字符串中被' ( '和' ) '包裹起来的子串和括号一起删除, 输出剩余字符串;

解题思路

用堆来存' ( '的位置, 每找到一个' ) '就删除最顶层左括号的位置, 将其匹配; 最后再遍历字符串, 跳过被标记的区间即可;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =1e6+10;
int n, m, k, idx;
vector<int> v;
map<int, int> mp;
signed main(){
	string s;
	cin >> n >> s;
	for (int i = 0; i < n; i++) {
		if (s[i] == '(') {
			v.push_back(i);
		}
		else if (s[i] == ')') {
			if (v.size() == 0) continue;
			int x = v.back();
			v.pop_back();
			mp[x] = i;

		}
	}
	for (int i = 0; i < n; i++) {
		if (mp[i]) i = mp[i];
		else cout << s[i];
	}
	return 0;
}




E - Distinct Adjacent

题目大意

n个编号为1~n的人按照数字大小做成一圈, 1与n相邻; 现在有0~m-1总共m个数字, 每个人从中选择一个数字, 共有mn种分配方式; 问有多少选择方式使得没有相邻的两个人选择的数字相同;

解题思路

这个题比较容易想到是一个dp问题; 而难点在于判断第n个人的状态, 而第n个人的状态计算时要考虑第( n-1 )个人和第1个人; 所以我们状态表示为f[i][1]和f[i][0], 前者表示前i个人中, 第1个人和第i个人数字相同的选择方式, 后者则是不同; 所以我们状态计算时, f[i][1] = f[i-1][0], f[i][0] = f[i - 1][0] * (m - 2) + f[i - 1][1] * (m - 1); 很明显f[i][1]是不合法的, 他只是运算过程中所需要的中间量, 所以结果就是f[n][0];
别忘了初始化, f[1][1] = m, f[1][0] = 0;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 10, mod = 998244353;
int n, m, k, idx;
int f[N][2], q[N];
signed main(){
	cin >> n >> m;
	f[1][1] = m;
	for (int i = 2; i <= n; i++) {
		f[i][1] = f[i - 1][0];
		f[i][0] = (f[i - 1][0] * (m - 2) + f[i - 1][1] * (m - 1)) % mod;
	}
	cout << f[n][0];
	return 0;
}




F - Virus 2

难度: ⭐⭐⭐⭐

题目大意

现在有n个房间, m条连通两个房间的走廊, 每条走廊都有各自的长度; 第0天有k个房间被污染了, 在往后的d天中, 每天都有一个范围xi, 在这一天中, 和污染房间之间最短距离小于等于xi的房间都会被污染; 最后输出每个房间被污染时是第几天, 如果没被污染就输出-1;

解题思路

题目所提到的范围x, 我们可以将其看作是两个房间之间走廊的长度, 如果该走廊的长度小于x且另一头是被污染的房间, 那么该房间就被污染了; 所以我们可以把有一边是污染房间的走廊的另一边的房间放进堆里, 按照走廊长度从小到大排序; 然后遍历所有x, 把走廊长度小于等于x的房间a取出, 并且由于这些房间现在已经被污染了, 所以我们也要遍历所有与他们相连的房间b也放进堆里; 注意, 这些新的房间中有的就在当前污染范围内, 这些可以直接放进堆(注意此时存的长度是wa+wb)里并且接着在这一天被处理; 而另外不在当天的污染范围内的就要在处理完当天后再放进堆里(此时存的长度就是wb); 为了避免重复, 被污染的房间要打上标记, 避免再被放进堆里; 根据上面的逻辑, 我们其实就是遍历了所有边, 再加上堆排序, 复杂度就O(m*nlogn); 由于给了4秒, 也算是惊险通过了;

神秘代码

#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 = 3e5 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m;
vector<PII> v[N];
int t[N];
bool st[N];
priority_queue<PII, vector<PII>, greater<PII>> heap;
queue<PII> q;
void ins(int x, int w,int d) {
    for (auto x : v[x]) {
        if (st[x.first]) continue;

        if (w + x.second <= d) heap.push({ w + x.second, x.first});
        else q.push({ x.second,x.first });
    }
}
signed main() {
    cin >> n >> m;
    memset(t, -1, sizeof t);
    for (int i = 1; i <= m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        v[a].push_back({ b,c });
        v[b].push_back({ a,c });
    }
    int k, d;
    cin >> k;
    for (int i = 1; i <= k; i++) {
        int a;
        cin >> a;
        t[a] = 0;
        st[a] = true;
        for (PII x : v[a]) heap.push({ x.second,x.first });
    }
    cin >> d;
    for (int i = 1; i <= d; i++) {
        int x;
        cin >> x;
        while (heap.size()&& heap.top().first <= x) {
            auto j = heap.top();
            heap.pop();
            if (!st[j.second]) {
                t[j.second] = i;
                st[j.second] = true;
                ins(j.second, j.first, x);
            }
        }
        while (q.size()) {
            heap.push(q.front());
            q.pop();
        }
    }
    for (int i = 1; i <= n; i++) cout << t[i] << endl;
    return 0;
}
posted @ 2023-06-26 18:07  mostimali  阅读(38)  评论(0编辑  收藏  举报