• AtCoder Beginner Contest 218 A~F 题解


    本场链接:AtCoder Beginner Contest 218

    A - Weather Forecast

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    #define x first
    #define y second
    
    int main()
    {
    	int n;string s;cin >> n >> s;
    	if(s[n - 1] == 'o')	cout << "Yes" << endl;
    	else cout << "No" << endl;
    	return 0;
    }
    

    B - qwerty

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    #define x first
    #define y second
    
    int main()
    {
    	forn(i,1,26)
    	{
    		int x;cin >> x;
    		cout << char(x + 'a' - 1);
    	}
    	cout << endl;
    	return 0;
    }
    

    C - Shapes

    首先考虑实现逆时针旋转整个字符数组:不难观察到相当于把每一列换到行上,并且第一列换到最后一行,第二列换到倒数第二行...如此可以将四种形态直接求出来,剩下的问题为:是否存在一种平移方式使得:两个图形重叠。可以以一定的顺序遍历所有黑点,如果存在一种平移的方式使得两个图形重叠,那么所有点相对偏移的坐标全部相同,抠出所有点进行check即可。

    注意形态一共有四种,可以不旋转,并且两个图形内的点数的个数不一定是相同的。甚至可以没有。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    #define x first
    #define y second
    
    const int N = 205;
    char s[N][N],t[N][N],r[N][N];
    
    bool solve(int n)
    {
    	vector<pii> target;	forn(i,1,n)	forn(j,1,n)	if(t[i][j] == '#')	target.push_back({i,j});
    	vector<pii> cur;	forn(i,1,n)	forn(j,1,n)	if(s[i][j] == '#')	cur.push_back({i,j});
    	if(target.size() != cur.size())	return 0;
    	if(target.empty())	return 1;
    	int dx = target[0].x - cur[0].x,dy = target[0].y - cur[0].y;
    	forn(i,0,target.size() - 1)	if(target[i].x - cur[i].x != dx || target[i].y - cur[i].y != dy)	return 0;
    	return 1;
    }
    
    int main()
    {
    	int n;scanf("%d",&n);
    	forn(i,1,n)	scanf("%s",s[i] + 1);
    	forn(i,1,n)	scanf("%s",t[i] + 1);
    
    	bool ok = 0;
    	forn(_,1,4)
    	{
    		forn(j,1,n)	forn(i,1,n)	r[n - j + 1][i] = s[i][j];
    		forn(i,1,n)	forn(j,1,n)	s[i][j] = r[i][j];
    		ok |= solve(n);
    	}
    
    	if(ok)	puts("Yes");
    	else puts("No");
    	return 0;
    }
    

    D - Rectangles

    显然考虑枚举两个点 ((i,j)),并且首先保证两个点满足:(y_i == y_j) 这样相当于枚举一条竖线。同时可以保证 (x_i < x_j) 这样 (i) 点一定在 (j) 点的上方,现在剩下的问题相当于求:有多少个二元组((z,k))满足这四个点可以形成一个矩形,那么首先前面的两个点 ((z,k)) 显然也必须要是一条竖线,并且保证 (x_z < x_k) 的前提下需要有: (x_z == x_i)(x_k == x_j)。如此可以直接用 map 维护二元组的数量,统计答案即可。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    #define x first
    #define y second
    
    const int N = 2005;
    pii p[N];
    
    int main()
    {
    	int n;scanf("%d",&n);
    	forn(i,1,n)	scanf("%d%d",&p[i].x,&p[i].y);
    
    	map<pii,int> st;
    	ll res = 0;
    	forn(i,1,n)	forn(j,1,n)
    	{	
    		int x1 = p[i].x,x2 = p[j].x,y1 = p[i].y,y2 = p[j].y;
    		if(y1 != y2 || x1 > x2 || i == j)	continue;
    		res += st[{x1,x2}];
    		++st[{x1,x2}];
    	}
    
    	printf("%lld
    ",res);
    	return 0;
    }
    

    E - Destruction

    删除一条边显然比较无理,考虑把问题逆向成建边,相当于一开始就把所有的边删掉,增加最少的边使得答案减少的最少,即答案的最大值。因为在这样反过来的问题上,正权边相当于减少权值,负权边相当于增加权值,所以所有负权边全部加入,并且正权边尽可能少,这样的问题答案等价于求 MST。直接套版子即可 (res = sum - MST)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    #define x first
    #define y second
    
    const int N = 2e5+7,M = 2 * N;
    struct Edge
    {
    	int u,v,w;
    	bool operator<(const Edge& rhs)	const
    	{
    		return w < rhs.w;
    	}
    }edges[M];
    int fa[N];
    int n,m;
    
    int find(int x)
    {
    	if(fa[x] == x)	return x;
    	return fa[x] = find(fa[x]);
    }
    
    ll kruskal()
    {
    	sort(edges + 1,edges + m + 1);
    	ll res = 0;
    	forn(i,1,m)
    	{
    		int u = edges[i].u,v = edges[i].v,w = edges[i].w;
    		u = find(u),v = find(v);
    		if(u == v)	
    		{
    			if(w < 0)	res += w;
    			continue;
    		}
    		fa[u] = v;
    		res += w;
    	}
    	return res;
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	forn(i,1,n)	fa[i] = i;
    
    	ll sum = 0;
    	forn(i,1,m)
    	{
    		int u,v,w;scanf("%d%d%d",&u,&v,&w);
    		edges[i] = {u,v,w};
    		sum += w;
    	}
    
    	printf("%lld
    ",sum - kruskal());
    	return 0;
    }
    		
    

    F - Blocked Roads

    因为所有边权为 (1),所以单次求解 SSSP 的复杂度是 (O(n + m))的,由于 (m = n^2)故单次求解为 (O(n^2))。那么直接暴力枚举删除所有边再拓展 BFS 求最短路的复杂度就是 (O(n^4))

    考虑首先求出一条最短路,不难想到:如果删去的边不在这条最短路上,那么删去他不会对最短路产生任何影响,所以答案不变。如果边就在最短路上,则在删除他的前提下直接 BFS,由于 (1 - n) 的最短路上至多有 (n-1) 条边,所以最多会额外跑 (n - 1) 次 BFS,这样产生的额外代价是 (O(n^3)) 的。整体的复杂度即 (O(n^3))。可以通过本题。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    #define forn(i,x,n) for(int i = x;i <= n;++i)
    #define forr(i,x,n) for(int i = n;i >= x;--i)
    #define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
    #define x first
    #define y second
    
    const int N = 405,M = N * N;
    int edge[M],succ[M],ver[N],ID[M],idx;
    int dist[N];
    int n,m;
    pii from[N];
    bool st[M];
    
    void add(int u,int v,int id)
    {
    	edge[idx] = v;
    	ID[idx] = id;
    	succ[idx] = ver[u];
    	ver[u] = idx++;
    }
    
    int bfs(int del = 0)
    {
    	memset(dist,0x3f,sizeof dist);dist[1] = 0;
    	queue<int> q;q.push(1);
    	while(!q.empty())
    	{
    		int u = q.front();q.pop();
    		for(int i = ver[u];~i;i = succ[i])
    		{
    			if(ID[i] == del)	continue;
    			int v = edge[i];
    			if(dist[v] > dist[u] + 1)
    			{
    				dist[v] = dist[u] + 1;
    				from[v] = {u,ID[i]};
    				q.push(v);
    			}
    		}
    	}
    	return dist[n] == 0x3f3f3f3f ? -1 : dist[n];
    }
    
    int main()
    {
    	memset(ver,-1,sizeof ver);
    	scanf("%d%d",&n,&m);
    	forn(i,1,m)
    	{
    		int u,v;scanf("%d%d",&u,&v);
    		add(u,v,i);
    	}
    
    	int res = bfs(),cur = n;
    	if(res == -1)
    	{
    		forn(i,1,m)	puts("-1");
    		return 0;
    	}
    	while(cur != 1)
    	{
    		int u = from[cur].x,id = from[cur].y;
    		st[id] = 1;
    		cur = u;
    	}
    	
    	forn(i,1,m)
    	{
    		if(!st[i])	printf("%d
    ",res);
    		else printf("%d
    ",bfs(i));
    	}
    	return 0;
    }
    
  • 相关阅读:
    PostgreSQL主备切换
    PostgreSQL流复制
    PostgreSQL存储过程(5)-异常错误处理
    PostgreSQL存储过程(4)-return语句
    vue+element ui项目总结点(二)table合计栏目,按照起始年份--截止年份 插入数据并向后追加数据以最后一条年份+1
    vue+element ui项目总结点(一)select、Cascader级联选择器、encodeURI、decodeURI转码解码、mockjs用法、路由懒加载三种方式
    react基础语法(五) state和props区别和使用
    js获取上周、本周、下周的时间
    Python基础语法(二)
    Python基础语法(一)
  • 原文地址:https://www.cnblogs.com/HotPants/p/15262872.html
Copyright © 2020-2023  润新知