Codeforces Round #771 (Div. 2)

A题.Reverse

 签到题,贪心+stl运用直接过.

抓住核心:最高位最大就行.

#include<bits/stdc++.h>
using namespace std;
int p[1020],a[1020];
int n;
int main()
{
	ios::sync_with_stdio(false);
    int t;
    cin>>t;
    int n;
    while(t--){
    	cin>>n;
    	int x;
    	for(int i=1;i<=n;i++){
    		cin>>x;
        	a[i]=x;
        	p[x]=i;
    	}
    for(int i=1;i<=n;i++){
        if(p[i]==i){
        	int flag=1;
        	continue;
		}
        reverse(a+i,a+p[i]+1);
        break;
    }
    for(int i=1;i<=n;i++)cout<<a[i]<<" ";
    cout<<"\n";
	}
}

B. Odd Swap Sort

  注意到只有两个数奇偶性不同才能互相交换位置。分别考虑奇数列和偶数列情况。

        如果奇数列或偶数列中有逆序存在,则原数列肯定不可能能够通过交换元素位置,达到非递减数列。

#include<bits/stdc++.h>
using namespace std;
vector<int>o,e;
int t,n;
int main()
{
	ios::sync_with_stdio(false);
    cin>>t;
    while(t--){
    	cin>>n;
		o.clear();
		e.clear(); 
    	for(int i=0;i<n;i++){
        	int x;
        	cin>>x;
        	if(x%2!=1)o.push_back(x);
        	else e.push_back(x);
    	}
    	int l1=o.size();
    	int l2=e.size();
    	int flag=1;
    	for(int i=1;i<l1;i++)if(o[i]<o[i-1]){
			cout<<"No\n";
			flag=0;
			break;
		}
		if(flag==0)continue;
    	for(int i=1;i<l2;i++)if(e[i]<e[i-1]){
		cout<<"No\n";
		flag=0;
		break;
		}
    	if(flag==0)continue;
		cout<<"Yes\n";
		}
}

C题.Inversion Graph

个人觉得挺好的一道题,题意大概就是找连通分量(connected components)的个数;虽然好像是个图论题,但其实只是用了图论的概念,本质其实就是个数据结构题。为什么这么说呢,由于只要两个数下标递增,值递减(即i<j,pi>pj即可建边)那么在寻找连通分量的时候,最直接的感觉就是一个最大的数会统治一个区间,最后统计这些数(或者区间数即可);但是感觉是需要经过打磨和落地的,那么配合样例来看一下。

首先这个显然为3,(搭个地基或者开个头)这里的基本算法思路就是当我们维护一个数组时,只要一直递增就一直计数。1 2 3 4 为4个 1 2 3 4 5 6为6个。当然没这么简单。

下一个样例我们发现,按照之前的思路还是可以做的,就是要做一点改动,就是我们由于我们要统计个数,先假设每个区间不互相干涉,所以只要留每个区间的max即可,最后统计一下个数就行。状态需要保留要回溯要剔除(pop)自然而然会联想到stack这种数据类型。那么框架又更搭的更进一步了

stack<int> s;
for(....)
cin>>x;
if(!s.empty()&&s.top()>x){
    ....
}
s.push_back(x);    //也就是说只要s非空或者输入的x>栈顶元素,那么就往里压,使得s.top()一直是max


 问题又来了,那如果是这样子的该怎么办,也就是说我们之前的方法不能正确的找到一个最大值统领的区域。原方法是3 5;但其实只有一个。也就是说5通过2联通了3,所以要把堆栈中的3剔除(pop)。如何实现呢,那么自然,把2想成一个通道,即如果x这个值小于5,那么还需要跟3比,如果小于3,那么相当于3跟5联通,那么3被提出。

把以上思路普遍化,就是当x<top()时,x不能不管了,要继续往下检查,如果x<s(某个值)。那么s就是被联通的,s.pop();再调试一下,就是以下解法:

AC代码:

#include <bits/stdc++.h>
using namespace std;
int t,n,i,x,y;
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);
	cin>>t;
	while (t--)
	{
		cin>>n;
		stack<int> s;
		while (n--)
		{
			cin>>x;y=x;
			if (!s.empty()&&s.top()>x)
			{
				y=s.top();s.pop();
				while (!s.empty()&&s.top()>x) s.pop();
			}
			s.push(y);
		}
		cout<<s.size()<<'\n';
	}
}

总结:要体会思路搭建的感觉,算法就是思路,有逻辑地思考问题,抽丝剥茧再加以变现,同时联想结构,结构是很重要的. 怎么吃一个问题,是我们需要学习的.问题真的会有很多吃法.

D. Big Brush

大概思路就是逆推,从最后开始,把大小为2X2一样色的换成0。0是万能色,不断倒推,最后顺着压栈输出。 

#include <bits/stdc++.h>
using namespace std;
const int mxn = 1e3 + 10;
const int mx = 1e6 + 10;
int g[mxn][mxn], n, m, sum, cnt, ans[3][mx];
void dfs(int x, int y) {
    if(x < 1 || y < 1 || x >= n || y >= m) return;
    int p = 0;
    for(int i = x; i <= x + 1; i ++)
        for(int j = y; j <= y + 1; j ++) {
            if(!p && g[i][j]) p = g[i][j];
            if(p && p != g[i][j] && g[i][j]) return;
        }
    if(!p) return;
    ans[0][++ cnt] = x, ans[1][cnt] = y, ans[2][cnt] = p;
    for(int i = x; i <= x + 1; i ++) 
        for(int j = y; j <= y + 1; j ++) 
            if(g[i][j]) sum ++, g[i][j] = 0;
    for(int i = x - 1; i <= x + 1; i ++) 
        for(int j = y - 1; j <= y + 1; j ++) {
            if(i == x && j == y) continue;
            dfs(i, j);
        }
}
int main() {
    ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for(int i  = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) cin >> g[i][j];
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++) {
if(g[i][j] == g[i + 1][j + 1] && g[i][j] == g[i][j + 1] && g[i][j] == g[i + 1][j] && g[i][j])
            dfs(i, j);
        }
    if(sum == n * m) {
        printf("%d\n", cnt);
        for(int i = cnt; i >= 1; i --)
            printf("%d %d %d\n", ans[0][i], ans[1][i], ans[2][i]);
    }
    else cout << -1 <<"\n";
    return 0;
}

第一次过1500,记录一下,情人节晚上打的.虽然运气成分很大,但也希望以后能越来越好.争取进队!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值