Codeforces Round #835 (Div. 4)

比赛链接:Dashboard - Codeforces Round #835 (Div. 4) - Codeforces

A: 排序

题意:给定三个数,求第二大数

思路:排一遍序,输出第二个数即可

代码:

#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int a[N];

inline void solve(){
	for(int i=1;i<=3;i++) cin>>a[i];
	sort(a+1,a+1+3);
	cout<<a[2]<<"\n"; 
}

signed main(){
	fast;
	int T;cin>>T;
	while(T--) solve();
}

B: 排序

 题意:找最大字符

思路:排序即可

代码:

#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int a[N];

inline void solve(){
	int n;string s;cin>>n>>s;
	sort(s.begin(),s.end());
	char aa=s[s.size()-1];
	int ans=aa-'a'+1;
	cout<<ans<<"\n";
}

signed main(){
	fast;
	int T;cin>>T;
	while(T--) solve();
}

C:贪心

题意:给定长度为N的数组,找每个数与最大数的差值,如果本身就是最大数,则差值为最大数-次大数 

思路:排一次序。依次运算即可

代码:

#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int a[N],b[N];

inline void solve(){
	int n;cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i],b[i]=a[i];
	sort(b+1,b+1+n);
	if(b[1]==b[n]){
		for(int i=1;i<=n;i++) cout<<"0 ";
		cout<<"\n";return;
	}
	for(int i=1;i<=n;i++){
		if(a[i]==b[n]) cout<<(a[i]-b[n-1])<<" ";
		else cout<<(a[i]-b[n])<<" ";
	}
	cout<<"\n";
}

signed main(){
	fast;
	int T;cin>>T;
	while(T--) solve();
}

D:思维+模拟

 这里直接说结论吧

结论:找到山谷后,后面的上升序列只能一直升,不能降

代码:

#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int a[N],d[N];

inline void solve(){
	int n;cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	bool ok=false;//表示是否为升序
	for(int i=2;i<=n;i++){
		if(a[i]==a[i-1]) continue;
		if(ok){
			if(a[i]<a[i-1]){
				cout<<"NO\n";return;
			}
		}
		if(a[i]>a[i-1]) ok=true;
	}
	cout<<"YES\n";
}

signed main(){
	fast;
	int T;cin>>T;
	while(T--) solve();
}

 E:前后缀

 题意:给定 01 串,求最多反转其中一个位置的前提下,最大的逆序对数

吐槽:一开始考虑贪心,直接搞TLE了。然后又O(N^2)求逆序对,也炸了。没有脑子捏。。。

思路:这里用前后缀进行优化

先算出初始的逆序对数量,接下来考虑每个点翻转对答案的影响。

如果是 0 变成 1 ,那么对答案的影响是减去后面的 1 的数量,加上前面 0 的数量。

如果是 1 变成 0 ,那么对答案的影响是减去后面 0 的数量,加上前面 1 的数量。

用前后缀分别维护出一个位置前面和后面 1 和 0 的数量即可。

代码:

#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int arr[N],p1[N],s1[N],p0[N],s0[N];
//p1:表示当前位置前面有多少个1
//p0:表示当前位置前面有多少个0
//s1:表示当前位置后面有多少个1
//s0:表示当前位置后面有多少个0

inline void solve(){
	int n;cin>>n;int sum=0;//sum记录逆序对数
	for(int i=1;i<=n;i++) cin>>arr[i];
	int a=0,b=0;//a表示1的个数,b表示0的个数
	for(int i=n;i>=1;i--){
		if(arr[i]==1){
			s1[i]=a;s0[i]=b;
			a++;sum+=b;
		}
		else{
			s1[i]=a;s0[i]=b;b++;
		}
	}
	a=0,b=0;
	for(int i=1;i<=n;i++){
		if(arr[i]==1){
			p1[i]=a;p0[i]=b;a++;
		}
		else{
			p1[i]=a;p0[i]=b;b++;
		}
	}
	int ans=sum;
	for(int i=1;i<=n;i++){//进行枚举判断
		if(arr[i]) ans=max(ans,sum+p1[i]-s0[i]);
		else ans=max(ans,sum-p1[i]+s0[i]);
	}
//ps:p0和s1数组没有用到捏...q.q
	cout<<ans<<"\n";
}

signed main(){
	int T;cin>>T;
	while(T--) solve();
}

 F:二分+贪心

题意:有 n 个任务,每个任务做完会获得 ai 的奖励,任务做完会有 x 天的 cd ,必须在 x+1 天才能继续完成这个任务。给定参数 c,d ,请问在 d 天获得至少 c 的奖励的最大cd是多少。

思路:先考虑特判,先从大到小sort一遍。

如果不存在冷却时间的情况下,如果每天都选择最大的得分(maxx),d*maxx<c,则无解。

再考虑无穷解的情况:同样如果不存在冷却时间的情况下,每天都选择一个数,sum记录和,如果sum>=c,则是无穷解。为什么?

因为,如果前面有一个大于c的,就可以是无穷解,或者是2个的和>c,或者是d个的和>c

然后就是考虑一半情况:这里选择二分答案

#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int a[N],n,c,d;

bool check(int mid){
	int sum=0;
	for(int i=1;i<=min(mid+1,n);i++){
		for(int j=i;j<=d;j+=mid+1){
			sum+=a[i];
			if(sum>=c) return true;
		}
	}
	return false;
}

inline void solve(){
    cin>>n>>c>>d;
	int maxx=0,sum=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];maxx=max(maxx,a[i]);
	}
	sort(a+1,a+1+n,greater<int>());
	for(int i=1;i<=min(d,n);i++) sum+=a[i];
	if(d*maxx<c) cout<<"Impossible\n";
	else{
		if(sum>=c){
			cout<<"Infinity\n";return;
		}
		int L=0,R=2e5;
		while(L+1<R){
			int mid=L+R>>1;
			if(check(mid)) L=mid;
			else R=mid;
		}
		cout<<L<<"\n";
    }
}

signed main(){
	int T;cin>>T;
	while(T--) solve();
}

G:DFS

题意: 给定一棵带边权的树,给定起点 a 和终点 b ,从 a 出发,刚开始的分数为 0 ,每走过一条边会使分数异或上这个值,要求最后走到 b 的分数为 0 ,并可以进行任意一次传送,求能否满足要求

思路:转化一下观点。从a到b,使得最终到达b时,xor为0。双向DFS一下。从a跑一遍,从b跑一遍。比如从a跑到点x的值为m,从b跑到点y的值为n,那么我们一定可以知道m==n

为什么?

因为题目中说了,可以传送一次点位,那么x点就可以直接传到y点,这样路径就连接起来了。

如果有交点怎么办?

其实交点就可以直接忽略掉,因为是xor,所以两条路径都有这个点,那么就xor为0了,可以直接消除。

所以最终做法:我们先搜一遍a,把xor值放入set中,再搜一遍b,判断xor值是否在set中出现即可

代码:

#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
typedef pair<int,int>PII;
int n,a,b;
vector<PII>ve[N];
set<int>se;
bool ok;

void dfs1(int u, int fa, int sum){
    se.insert(sum);
    for(auto [x, y] : ve[u]){
        if(x == fa) continue;
        if(x != b)
        dfs1(x, u, sum ^ y);
    }
}

void dfs2(int u, int fa, int sum){
    for(auto [x, y] : ve[u]){
        if(x == fa) continue;
        if(se.count(sum ^ y)) ok = 1;
        dfs2(x, u, sum ^ y);
    }
}

void solve(){
    cin >> n >> a >> b;
    ok = false;se.clear();
    for(int i = 1; i <= n; i ++ ) ve[i].clear();
    for(int i = 1; i <= n - 1; i ++ ){
        int x, y, z;cin >> x >> y >> z;
        ve[x].push_back({y, z});
		ve[y].push_back({x, z});
    }     
    dfs1(a, 0, 0);dfs2(b, 0, 0);
    if(ok) cout << "YES\n";
    else cout << "NO\n";
}

signed main(){
	int T;cin>>T;
	while(T--) solve();
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值