Codeforces Round 974 (Div.3) A-E

A.Robin Helps

算法:模拟

按照题意模拟即可(数据范围很小)A-E

需要注意当先我手中有黄金时才可以给

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

const int N = 60;

int T,n,k;

void solve(){
    cin >> n >> k;
    
    int ans = 0, res = 0;
    for(int i = 0; i < n; i++){
        int x;
        cin >> x;
        
        if(x >= k) res += x;
        else if(!x){  //当前ai = 0 ,那么给一个黄金 
            
            if(res >= 1) {  //我手里有黄金时才能给 
                res--;
                ans ++;   //给黄金的人数 
            }
        }
    }
      cout << ans << endl;
       
}
int main(){
    cin >> T;
    
    while(T--){
        solve();
    }
    return 0;
}


B.Robin Hood and the Major Oak

算法: 数学

思路:
判断区间内奇数个数是否为偶数即可

分情况讨论:

(1)k >= n 时, 说明叶子能存活到第n年

用n % 4 来判断可行

比如:1  2  3  4
     x  x  o  o

因此,
     string s = n % 4 == 3 || n % 4 == 0 ? "YES" : "NO";


(2) k < n时,用 k(寿命值来进行取模运算)
 

分两种情况来讨论:两种情况都是从后往前倒着看

1)第n年为奇数时,最后一年为奇数年 
    2  3  4  5
    o  o  x  x      
2)第n年为偶数时,最后一年为偶数年
    1  2  3  4
    o  x  x  o  
C++代码
#include <bits/stdc++.h>
using namespace std;

int T,n,k;

void solve(){
    cin >> n >> k;
    
    string s = "";
    if(k >= n){
        //1 2 3 4 5
        s = n % 4 == 3 || n % 4 == 0 ? "YES" : "NO" ;
    
    }
    
    //1 2 3 || 2 3 4 5
    else if(n % 2 == 1) //n & 1
    {
        s = k % 4 == 1 || k % 4 == 2 ? "NO" : "YES";
    }
    //1 2 3 4
    else{
        s = k % 4 == 2 || k % 4 == 3 ? "NO" : "YES";
    }
    cout << s << endl;
}
int main(){
    cin >> T;
    while(T--){
        solve();
    }
    return 0;
}


C.Robin Hood in Town

算法: 二分

思路:

1.理解题意

什么时候罗宾汉出现呢?

当且仅当**不快乐的人数**严格大于总人口数的一半的时候

什么是不快乐的人数?

一个人的财富**严格少于平均财富的一半**,那么这个人就是不快乐的人。

2.为何用二分?

1)满足单调性  2)求罗宾汉出现的最小的x

由于我们需要求的x的数是最小的,因此左向逼近

用l + r >> 1 板子即可


C++代码
 
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10;

int T,n,sum;
int a[N];

bool check(int x){
    double ave = (sum + x) * 1.0 / (2.0 * n);
    
    int cnt = 0;  //不快乐的人数
    
    for(int i = 1; i <= n; i++){
        if(a[i] < ave) cnt ++;
    } 
    return cnt > n / 2;  //是否一半以上的人为不快乐的人 
} 
void solve(){
    memset(a,0,sizeof a);  
    sum = 0;
    
    cin >> n; 
    
    for(int i = 1; i <= n; i++){
        cin >> a[i];
        sum += a[i];
    }
    
    if(n <= 2) {
        cout << "-1" << endl;
        return;
    }
    
    int l = 0, r = 1e18;
    while(l < r){
        int mid = l + r >> 1;  //找到最小的x;因此左向逼近
        if(check(mid)) r = mid;
        else l = mid + 1; 
    }
    cout << l << endl;    //最小的x值 
}
signed main(){
    cin >> T;
    while(T--){
        solve();
    }
    return 0;
}


D.Robert Hood and Mrs Hood

算法: 滑动窗口,双指针

详细写在注释当中

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

const int N = 1e5 + 10;

int T,n,d,k;

void solve()
{
	cin >> n >> d >> k;
	
	vector<int>in(n+1);   //开始的天数 
	vector<int>out(n+1);  //结束的天数
	
	//输入k个任务的开始与结束时间 
	for(int i = 1; i <= k; i++){
		int x,y;
		cin >> x >> y;
		in[x] ++;
		out[y]++;
	}
	
	int cnt = 0; //区间内任务的个数
	int bro = -1, mo = k + 1;
	
	//区间内开始的工作数量 
	for(int i = 1; i < d; i++){
		cnt += in[i];
	} 
	int b = -1, m = -1;
	for(int i = 1; i + d - 1 <= n; i ++){
		cnt -= out[i - 1];    //当前区间内结束的任务个数
		cnt += in[i + d - 1];   //往后移动区间是区间内增加的任务数
	    
	    if(cnt > bro) {
	    	bro = cnt;
	    	b = i;   //哥哥入住的日期 
		}
		if(cnt < mo) {
			mo = cnt;
			m = i;
		} 
		 
	}
     cout << b << " " << m << endl ;
	
}
int main(){
	cin >> T;
	while(T--){
		solve();
	}
	return 0;
}


E. Rendez-vous de Marian et Robinsuan

算法: 最短路

思路:

边权都是正数,我们可以用dijkstra 堆优化算法,而且是个稀疏图我们可以用邻接表来存储每一条边

玛丽亚在起点,罗宾在终点

如果不考虑马我们跑两遍dijkstra,从起点跑一遍最短路,从终点跑一遍最短路,最后再枚举相遇点,取最小值;

由题意可知,骑马之后所有时间点会减少一半(读题的时候误解这一部分,以为只有下一个点的时间减少一半)

1.首先我们要明确骑马之后不用再走已经走过的路,这里可以用vis[]来标记访问情况

难点:

2.走路到骑马的转换关系:

我们再开一个数组标记该点处是否有马;

pair<int,pair<int,bool> > q;

//第一个数据存放的是距离,按照距离的大小进行从小到大进行排序的

//第二个数据存放的是该结点的编号

//第三个数据存放的是该点是否有马的情况
C++代码
#include <bits/stdc++.h>
using namespace std;

#define int long long
typedef pair<int,int>PII;
const int INF = 1e18; 

int T,n,m,h;

void dijkstra(vector<vector<PII>>& g,vector<vector<int>>& dist,vector<bool>&hs,int start){
	
	vector<vector<bool> > st(n+1,vector<bool>(2,false));
	priority_queue<pair<int,pair<int,bool>>,vector<pair<int,pair<int,bool>>>,greater<pair<int,pair<int,bool>>>>q;
	
	dist[start][0] = 0;
	q.push(make_pair(0,make_pair(start,0)));
	
	while(!q.empty()){
		auto t = q.top();
		q.pop();
		
		int ver = t.second.first;
		bool u = t.second.second;
		
		bool horse = ( u || hs[ver]);
		
		if(st[ver][horse]) continue;
		st[ver][horse] = true;
		
		for(auto [j,w] : g[ver])   //枚举所有ver结点的邻接点 
		{
			int val = horse ? w / 2 : w;   //当前是否再骑马
			if(dist[j][horse] > dist[ver][u] + val){
				dist[j][horse] = dist[ver][u] + val;
				q.push({dist[j][horse],{j,horse}});
			} 
		}
	}
	
}
void solve(){
	cin >> n >> m >> h;
	
	vector <bool> hs(n + 1);
	
	while(h--){
		int x;
		cin >> x;
		hs[x] = true;
	}
	
	vector<vector<PII>> g(n+1);
	
	while(m--){
		int a,b,w;
		cin >> a >> b >> w;
		//建立无向图 
		g[a].push_back(make_pair(b,w));
		g[b].push_back(make_pair(a,w));
	}
	
	vector<vector<int>> dist1(n+1,vector<int>(2,INF));
	vector<vector<int>> dist2(n+1,vector<int>(2,INF));
	
	dijkstra(g, dist1, hs, 1);
	dijkstra(g, dist2, hs, n);
	
	//lambda:引用铺货
	auto get = [&] (int a)
	{
		return max(min(dist1[a][0],dist1[a][1]),min(dist2[a][0],dist2[a][1]));
	 };
	 
	 //枚举相遇点
	 int ans = INF;
	 for(int i = 1; i <= n; i++){
	 	ans = min(ans,get(i));
	 } 
	 if(ans == INF) cout << "-1" << endl;
	 else cout << ans << endl;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	cin >> T;
	while(T--){
		solve();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值