Codeforces Good Bye 2021: 2022 is NEAR ABCDE

A. Integer Diversity

统计所有数字中,绝对值不同的数字的个数,当且仅当绝对值个数小于2时才统计

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=200100;
int n,m,t;
int w[N];
int cw[N];
int main(){
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		for( int i=0;i<n;i++){
			scanf("%d",&w[i]);
		}
		multiset<int>se;
		for( int i=0;i<n;i++){
			int x=abs(w[i]);
			if(x!=0)
				if(se.count(x)<2)se.insert(x);
			if(x==0)
				if(se.count(x)<1) se.insert(x);
		}
		cout<<se.size()<<endl;
		
	}
}

B. Mirror in the String

分类讨论,当字符串开头有两个相同字母时,直接输出两个开头字母,否则输出单调递减字符序列,直到遇到单调递增的序列。
作图分析会更清晰。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=200100;
int n,m,t;
int w[N];
int cw[N];
int main(){
	cin>>t;
	while(t--){
		cin>>n;
		string s;
		cin>>s;
		string ans;
		ans+=s[0];
		int flag=0;
		for( int i=1;i<s.size();i++){
			if(s[i]<*(--ans.end())){
				ans+=s[i];
				flag=1;
			}
			else if(s[i]==*(--ans.end())){
				if(flag==0) break;
				else ans+=s[i];
			}
			else break;
		}
		cout<<ans;
		reverse(ans.begin(),ans.end());
		cout<<ans<<endl;
	}
	return 0;
}

C. Representative Edges

枚举数列中的任意两个点,然后计算斜率,判断多少个点在直线上,注意精度问题。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=200100;
int n,m,t;
int w[N];
int cw[N];
int eq(double x,double y){
	return fabs(x-y)<1e-7;
}
int check( double x,int val,int pos){
	int res=0;
	for( int i=0;i<n;i++){
		if(eq(1.0*w[i]-val,x*(i-pos))) ;
		else res++;
	}
	return res;
}
int main(){
	cin>>t;
	while(t--){
		cin>>n;
		
		for( int i=0;i<n;i++){
			scanf("%d",&w[i]);
		}
		if(n==1){
			cout<<0<<endl;
			continue;
		}
		int ans=inf;
		for( int i=0;i<n;i++){
			for( int j=0;j<i;j++){
				double div=(1.0*w[i]-w[j])/(i-j);
				ans=min(ans,check(div,w[i],i));
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

D. Keep the Average High

题目大意:将一个区间划分为任意个子区间,每个子区间满足:
该区间任意子区间平均值大于x

状态dp
只需讨论最后两个数选与不选,一共四种情况。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=200100;
int n,m,t;
int w[N];
int dp[N][4];//00 0代表后两个都不选,01 1代表后一个选,10 2代表,11 3代表
int main(){
	cin>>t;
	while(t--){
		cin>>n;
		for( int i=1;i<=n;i++){
			scanf("%d",&w[i]);	
		}
		int x;
		cin>>x;
		for( int i=1;i<=n;i++){
			dp[i][0]=max(dp[i-1][0],dp[i-1][2]);
			dp[i][1]=max(dp[i-1][0],dp[i-1][2])+1;
			dp[i][2]=max(dp[i-1][1],dp[i-1][3]);

			if(i==1) {
				dp[i][3]=1;
			}
			else if(i==2){
				if(w[i]+w[i-1]>=x+x) dp[i][3]=2;
				else dp[i][3]=-inf;
			}
			else{
				if(w[i]+w[i-1]>=x+x&&w[i]+w[i-1]+w[i-2]>=x+x+x)
					dp[i][3]=max(dp[i-1][1],dp[i-1][3])+1;
				else if(w[i]+w[i-1]>=x+x)
					dp[i][3]=dp[i-1][1]+1;
				else dp[i][3]=-inf;
			}
		}
		int ans=0;
		for( int i=0;i<4;i++){
			ans=max(dp[n][i],ans);
		}
		cout<<ans<<endl;
		
	}
}

E. Lexicographically Small Enough

数据结构。
假如前面的若干位都相等,要取得最小值,有两种策略,第一种策略是将本位换成比原来为小的数值,第二种策略是将本位换成与原来位相同的数值,然后再递归。
如果暴力实现,每次需要便利一次整个数组,时间复杂度为n*n
可以使用set优化,在logn的时间内找到比原数大或相等的且距离最近的数。
但是在两数相等的情况下,由于交换,数的位置会发生变化,因此需要一个数据结构来维护这个变化量。
维护的方法有很多,可以使用树状数组,线段树,平衡树等。
这里使用平衡树,用平衡树记录每个交换数的原位置。对于每次查询,只需查找后面有几个数被交换到前面,即可计算出位置的改变量。
注意需要开longlong

#include <bits/stdc++.h>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
const ll inf=1e15;
const int N=200100;
int n,m,q;
string s,t;
int cnt[26];
tree<int,null_type,greater<int>,rb_tree_tag,tree_order_statistics_node_update>delete_pos;
int f(int x){
	return x+delete_pos.order_of_key(x);
}
signed main(){
	cin>>q;
	while(q--){
		cin>>n>>s>>t;
		memset(cnt,0,sizeof(cnt));
		delete_pos.clear();
		set<int>se[26];
		for( int i=0;i<s.size();i++){
			cnt[s[i]-'a']++;
			se[s[i]-'a'].insert(i);
		}
		ll ans=inf,cnt_swap=0;
		for( int i=0;i<t.size();i++){
			int x=t[i]-'a',y=s[i]-'a';
			int flag=0;
			for( int j=0;j<x;j++){
				if(cnt[j]){
					ans=min(ans,cnt_swap+f(*se[j].begin())-i);
					flag=1;
				}
			}
			if(cnt[x]){
				flag=1;
				int posx=*se[x].begin(),posy=*se[y].begin();
				delete_pos.insert(posx);
				cnt_swap+=f(posx)-i;
				se[x].erase(se[x].begin());
				cnt[x]--;
			}
			else break;
			if(flag==0){
				break;
			}
		}
		if(ans==inf) printf("-1\n");
		else printf("%lld\n",ans);
		endd:;
	}	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值