Codeforces Round #744 (Div. 3)(A-E2)

首先,庆祝自己上了绿名
在这里插入图片描述
A. Casimir’s String Solitaire
题目描述:
一个字符串包括A,B,C三种字符,有俩种操作可以选择
1.删除一个A和一个B
2.删除一个B和一个C
问最后能不能将这个字符串清空
思路:
统计A,B,C的数量为a,b,c,b=a+c则YES,否则NO

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

#define int long long

signed main(){
	int t;
	cin>>t;
	while(t--){
		int a=0,b=0,c=0;
		string s;
		cin>>s;
		for(int i=0;i<s.length();i++){
			if(s[i]=='A')a++;
			if(s[i]=='B')b++;
			if(s[i]=='C')c++;
		} 
		if(b==a+c)cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	
	return 0;
}

B. Shifting Sort
题目描述:
对于给定的序列,[l,r]代表选择的区间,d代表前d位不动,区间后几位移动到最前面去,
例如[2,3,4,5,6,7]选择区间[1,5],d为2则->[4,5,6,2,3,6,7]
问给定的序列,使用不多于n次这样的操作使得整个序列不降序排列
思路:
从下标2开始,找到第一个大于它的数(因为n比较小,可以之间暴力遍历),将它插进去(需要调整整个区间),通过开三个数组l,r.d记录每次操作的l,r,d.l[k]为第一个大于它的数,r[k]为它前面的第一个数,d[k]为这段的长度.

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

#define int long long
int a[100];
int l[100],r[100],d[100];
signed main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		for(int i=1;i<=n;i++){
			scanf("%lld",&a[i]);
		}
		int k=0;
		for(int i=2;i<=n;i++){
			int flag=i;
			for(int j=1;j<i;j++){
				if(a[j]>a[i]){
					int temp=a[i];
					for(int p=i;p>j;p--){
						a[p]=a[p-1];
					}
					a[j]=temp;
					flag=j;
					break;
				}
			}
			if(flag!=i){
				l[k]=flag;
				r[k]=i;
				d[k++]=i-flag;
			}
		}
		cout<<k<<endl;
		for(int i=0;i<k;i++){
			cout<<l[i]<<" "<<r[i]<<" "<<d[i]<<endl;
		}
	}
	
	return 0;
}

C. Ticks
题目描述:
对于n*m的方格,里面有一些⭐的点,对于给定的k,能不能画长度大于k的v图案使得所有的⭐都被覆盖过

思路:
n不大,直接暴力模拟

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

#define int long long
//char c[20][25];
int flag[20][25];
string c[20];
signed main(){
	int t,l;
	cin>>t;
	while(t--){
		int n,m,k,left,right,up,o=1;
		cin>>n>>m>>k;
		for(int i=1;i<=n;i++){
			cin>>c[i];
			c[i]=" "+c[i];
			for(int j=1;j<=m;j++){
				l=0;
				flag[i][j]=0;
				if(c[i][j]=='*'){
					flag[i][j]=1;
					left=j,right=j,up=i;
					while(up>=2&&left>=2&&right<=m-1&&c[up-1][left-1]=='*'&&c[up-1][right+1]=='*'){
						l++;
						left--;
						right++;
						up--;
					}
					if(l>=k){
						left=j,right=j,up=i;
						flag[i][j]=0;
						while(up>=2&&left>=2&&right<=m-1&&c[up-1][left-1]=='*'&&c[up-1][right+1]=='*'){
							flag[up-1][left-1]=0;
							flag[up-1][right+1]=0;
							left--;
							right++;
							up--;
						}
					}
				}
				
			}
			
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				if(flag[i][j]==1){
					cout<<i<<" "<<j<<endl;
					o=0;
					break;
				}
			}
		}
		if(o)cout<<"YES"<<endl;
		else cout<<"NO"<<endl; 
	}
	
	return 0;
}

D. Productive Meeting
题目描述:
给定一个序列的人,每个人都有一些谈话次数,问这个序列最多能进行谈话多少次

思路:
每次找到拥有谈话次数最多的人,让他与谈话次数最少的人进行一次谈话,不断模拟这个过程,可以用set完成这种操作

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

#define int long long
set<pair<int,int> > st;
int l[200005],r[200005];
signed main(){
	int t;
	scanf("%lld",&t);
	while(t--){
		int n;
		scanf("%lld",&n);
		int a;
		for(int i=1;i<=n;i++){
			scanf("%lld",&a);
			if(a!=0)st.insert(pair<int,int>(a,i));
		} 
		int k=0;
		while(st.size()>1){
			auto q=*st.begin();
			auto p=*st.rbegin();	
			q.first--;
			p.first--;	
			if(p.second>q.second){
				l[k]=q.second;
				r[k]=p.second;
			}
			else{
				l[k]=p.second;
				r[k]=q.second;
			}
			k++;
			st.erase(st.begin());
			if(p.first>0){
				st.insert(pair<int,int> (p.first,p.second));
			}
			auto it=st.end();
			it--;
			st.erase(it);
			if(q.first>0){
				st.insert(pair<int,int> (q.first,q.second));
			}
		}
		printf("%lld\n",k);
		for(int i=0;i<k;i++){
			printf("%lld %lld\n",l[i],r[i]);
		}
		st.clear();
	}
	
	return 0;
}

E1. Permutation Minimization by Deque

题目描述:
对于给定的序列,你可以按照从左到右的顺序将每个点选择添加到队列的头或者尾部,问这样操作下来能得到字典序最小的序列是怎样的

思路:
贪心的想法,拿21312来讲,先将2放进去,对于1来讲,2>1,1放在前面就可以降低字典序,所以1放前面,然后对于3来讲,队列头为1,3放前面则会提高字典序,3放后面,然后对于1来讲,队列头为1,将1放在前面显然比1放在后面的字典序小,
所以得出一个结论,对于当前的点来说,比队列头小或者等于则放在前面,或者放在后面,具体的实现可以用双端队列来完成.

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

signed main(){
	int t;
	scanf("%lld",&t);
	while(t--){
		int n;
		scanf("%lld",&n);
		deque<int> q;
		int a;
		scanf("%lld",&a);
		q.push_back(a);
		for(int i=2;i<=n;i++){
			scanf("%lld",&a);
			if(a>q.front())q.push_back(a);
			else q.push_front(a);
		}
		while(!q.empty()){
			printf("%lld ",q.front());
			q.pop_front();
		}
		printf("\n");
	}
	
	return 0;
}

E2. Array Optimization by Deque

题目描述:
与E1题描述差不多,但是所求完全不一样,这题通过选择放前面或者放后面的操作最终达到逆序对最小的序列

思路:
思路很简单,对于当前要放进去的点,考虑它与之前的点逆序的情况,也就是这个点当前贡献的逆序对,当之前的点比它小的数比它大的数多,则放前面会形成更少的逆序对,反之,放后面会形成更少的逆序对,一开始我选择通过set容器维护这个操作,set容器是有序的,通过二分查找就能判断当前点对应之前点的位置,不过,这个只能返回一个迭代器,而得不到下标,想法破灭(查了很多资料也没有得到set下标的方法,有会的大佬可以教一下),然后看别人题解是用树状数组求逆序对的方法,因为ai的范围为[-1e9,1e9],所以这个不能用值作为下标,可以将整个数组排序,然后去重,找到该值对应的序号作为下标.接下来就是树状数组求逆序对的板子了

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

#define int long long
int cnt,n;
int c[100005];
int a[100005]; 
vector<int> all;
int lowbit(int x){
	return x&(-x);
}

void updata(int i,int v){
	while(i<=n){
		c[i]+=v;
		i+=lowbit(i);
	}
}

int getsum(int i){
	int res=0;
	while(i){
		res+=c[i];
		i-=lowbit(i);
	}
	return res;
}

//deque<int> q;
signed main(){
	int t;
	scanf("%lld",&t);
	while(t--){
		cnt=0;
		scanf("%lld",&n);
		for(int i=1;i<=n;i++){
			c[i]=0;
			scanf("%lld",&a[i]);
			all.push_back(a[i]);
		}
		sort(all.begin(),all.end());
		all.erase(unique(all.begin(),all.end()),all.end());
		for(int i=1;i<=n;i++){
			a[i]=lower_bound(all.begin(),all.end(),a[i])-all.begin()+1;	
			int l=getsum(a[i]-1);
			int t=getsum(a[i])-getsum(a[i]-1);
			if(l<=(i-l-1-t))cnt+=l;
			else cnt+=(i-l-1-t);
			cout<<cnt<<endl;
			updata(a[i],1);
		}
		printf("%lld\n",cnt);
		all.clear();
	}
	
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值