CF-932(已更新 A B)

CF-932(已更新 A B)

之前的CF也都掉分了的打了的,只是都还没补题……

逆天舍友打游戏看抖音都外放-^-,打游戏生气了还要大声地祖安别人……

A

赛时只想到了在暴力的做法,写得还巨丑,鉴定为天天喝八宝粥喝的(⊙﹏⊙)

分析

题意已经如此直白而自己赛时居然一直在死磕一个最复杂的写法

操作

  1. 用两个指针l,r分别从最前面与最后面开始遍历,只要先出现s[l]<s[r],就说明不需要翻转,而先出现s[l]>s[r],说明需要翻转
  2. 操作次数是偶数,意味着输出的字符串只有两种情况:原字符串s或反转后的字符串+s,答案要求字典序最小,只需要输出两者的较小的一个

代码

自己调的虽然但是,它只跑了0ms

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define db(x) cout<<x<<" "<<endl;
#define _db(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a) memset(a,0, sizeof(a))
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
void solve(){
	int n;cin>>n;
	string s;cin>>s;	
	int r=s.length()-1,l=0;
    int f=1;
	while(l<r){
       if(s[l]<s[r]){
           f=1;
           break;
       } 
       else if(s[l]>s[r]){
           f=0;
           break;
       }
       l++,r--;
    }
    if(f) cout<<s;
	else{
		string ss=s;
		reverse(s.begin(),s.end());
		cout<<s<<ss;
	}
	cout<<endl;
}
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
	int t;cin>>t;while(t--)
	solve();
	return 0;
}

 

看了题解写的虽然但是,它跑了15ms

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define db(x) cout<<x<<" "<<endl;
#define _db(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a) memset(a,0, sizeof(a))
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
void solve(){
	int n;cin>>n;
	string s;cin>>s;	
	string ss=s;
	reverse(s.begin(),s.end());
	s+=ss;
	cout<<min(s,ss)<<endl;
}
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
	int t;cin>>t;while(t--)
	solve();
	return 0;
}

 

B

自己赛时就没想明白,看题解的思路才懂是怎么个事

调了两小时(⊙﹏⊙),这样看来是我赛时过不了的题……我这题解有写的必要╰(°▽°)╯

……看了题解的代码,只能说我是sb还有很大优化空间


分析

即找到的区间要满足最小的未在区间内出现过的数op相同,这些区间又包含了a数组的所有元素,所以op一定是a数组中未出现过的数的最小值,又因为要找的区间的op都要相同,所以我们可以干脆就找2个合法的区间就行

如[0 1 7] 这个数是2,[1,1,2] 这个数是0,[2,2,2] 这个数是0

操作

要找最小的未在区间内出现过的数op,可以在输入时记录出现每个数的出现次数及最大值mx,然后遍历0到mx+1,当遍历到的第一个未出现就是op;对于找两个区间,它们必须都含有[0,op)内的所有数,为此,我们可以先用set存下[0,op)内的所有数,用左右两个指针ll,rr分别从数组两边开始遍历,如果左边与右边比op小的数都至少出现1次,说明存在这两个合法区间,两个区间的分界点可以是rr-1与rr或者ll与ll+1

代码

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define db(x) cout<<x<<" "<<endl;
#define _db(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a) memset(a,0, sizeof(a))
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
const int N=1e5+5;
int a[N],l[3],r[3];
void solve(){
	int n;cin>>n;
	map<int,int>mp;
	int mx=0;
	rep(i,1,n){
		cin>>a[i];
		mx=max(a[i],mx);
		mp[a[i]]++;
	}
	set<int>s;
    //int op=0;
	rep(i,0,mx+1){
		if(!mp[i]){
            //op=i;
			break;
		}
		s.insert(i);
	}
	l[1]=1,r[2]=n;
	// 0 1 7| 1 0 |1 0 3  -> 0 1 7 1 0 | 1 0 3 
	//左边与右边比op小的数都至少出现1次 
	// 0 1 1 
	// 1 1 2
	int ll=1,rr=n,ls=0,rs=0,f=1;
	map<int,int>lmp,rmp;
	while(ll<rr){
		if(ls==rs&&ls==s.size()){
			f=0;
			l[2]=rr,r[1]=rr-1;
			break;
		}
		if(!lmp[a[ll]]&&s.count(a[ll])) ls++;
		if(!rmp[a[rr]]&&s.count(a[rr])) rs++;
		lmp[a[ll]]=1,rmp[a[rr]]=1;
		if(ls<s.size()) ll++;
		if(rs<s.size()) rr--;
	} 
	if(f){
		cout<<-1<<endl;
		return;
	}
	cout<<2<<endl;
	rep(i,1,2){
		cout<<l[i]<<" "<<r[i]<<endl;
	}
}
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
	int t;cin>>t;while(t--)
	solve();
	return 0;
}

posted @ 2024-03-06 20:54  mono_4  阅读(11)  评论(0编辑  收藏  举报