Codeforces Round #763 (Div. 2) 部分题解(A-C)

Codeforces Round #763 (Div. 2)

 

A - Robot Cleaner
思维
题意:n*m的地图,一个机器人初始在一个位置,一开始往右下方走,碰到墙壁就改变方向,类似于光的折射(原题有图),每次可以清理和机器人同行或同列的格子,问最少几步清理目标.
 
思路:数据范围很小,模拟一下就可以了,类似于dfs的函数,记录好方向坐标。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    #define mem(a,b) memset(a,b,sizeof a)
    using namespace std;
    typedef long long int ll;
    typedef pair<int, int> pii;
    const int N = 105;
    bool flag = false;
    int ans = 0;
    int n, m, sx, sy, ex, ey;//地图尺寸,起点,终点
    //x,y表示当前走到哪里,now表示步数,xx,yy表示上一步的方向坐标
    void dfs(int x, int y,int now,int xx,int yy) {
    	if (x == ex || y == ey|| flag) {
    		ans = now;
    		flag = true;
    		return;
    	}
    	int tx = xx, ty = yy;
    	if (x == n) tx = -1; if (x == 1) tx = 1;
    	if (y == m) ty = -1; if (y == 1) ty = 1;
     
    	dfs(x + tx, y + ty, now + 1, tx, ty);
    	return;
    }
     
    void solve() {
    	cin >> n >> m >> sx >> sy >> ex >> ey;
    	ans = 0; flag = false;
    	dfs(sx, sy, 0, 1, 1);
    	cout << ans << endl;
    }
     
    int main() {
    	ios::sync_with_stdio(false);
    	int t; cin >> t;
    	while(t--)
    	solve();
     
    	return 0;
    }

 
B - Game on Ranges
 
广搜
题意:一个1-n的集合,n个[l,r],每次在区间中选一个数删掉,问完全删完1-n的方法.
 
思路:数据范围很小,所以可以考虑广搜,开始加入区间内所有数入队,每个结点用set维护已经选了哪些数,如果已经被选中直接跳过,最后肯定会有一个可行解。
MLE了一次,sort区间长度从小到大后过了,其实一开始就想到了优化搜索树,没看到题目里说区间可以任意顺序,🤭。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    #include<set>
    #include<queue>
    #define mem(a,b) memset(a,b,sizeof a)
    using namespace std;
    typedef long long int ll;
    typedef pair<int, int> pii;
    const int N = 1e3 + 5;
    typedef struct node {
    	set<int> s;
    	vector<int> p;
    };
    bool cmp(pii a, pii b) {
    	return abs(a.second - a.first) < abs(b.second - b.first);
    }
    void solve() {
    	int n;
    	cin >> n;
    	pii a[N];
    	mem(a, 0);
    	for (int i = 1; i <= n; i++) {
    		int l, r; cin >> l >> r;
    		a[i].first = l;
    		a[i].second = r;
    	}
    	sort(a + 1, a + 1 + n, cmp);
    	
    	vector<int> ans;
    	queue<node> q;
    	//把长度最小的区间派生出的结点们入队
    	for (int i = a[1].first; i <= a[1].second;i++) {
    		node now;
    		now.p.push_back(i);
    		now.s.insert(i);
    		q.push(now);
    	}
     
    	while (!q.empty()) {
    		node now = q.front();
    		q.pop();
    		if (now.p.size() == n) {//得到答案
    			ans = now.p;
    			break;
    		}
    		int cnt = now.p.size() + 1;//cnt表示下一个区间编号,注意要+1
    		int l = a[cnt].first, r = a[cnt].second;
    		for (int i = l; i <= r; i++) {
    			if (now.s.count(i)) continue;//数已经出现过,跳过
    			node temp = now;
    			temp.s.insert(i);//更新
    			temp.p.push_back(i);
    			q.push(temp);
    		}
    	} 
     
     
    	for (int i = 1; i <= n; i++) {
    		cout << a[i].first << " " << a[i].second << " " << ans[i - 1] << endl;
    	}
    	
    }
     
    int main() {
    	ios::sync_with_stdio(false);
    	int t; cin >> t;
    	while (t--)
    		solve();
     
    	return 0;
    }

 
C_Balanced Stone Heaps
 
二分
题意:n堆石子,从第三个开始,可以选择:1.拿出3*d份,给n-1分d份,给n-2分2d份,2.不操作。问这样操作后最小堆的最大值是多少
思路:看到最大化最小值,就能想到二分。如果从前往后二分,每一次还要考虑更新后的结果。所以我们从后往前二分,因为每堆石子只能被他后面的影响,并且分给前面的,所以设二分值k为答案,从后往前遍历,如果当前石头原始就小于k,表示在后面已经合法分完的情况下,当前堆还是小于想要的答案,所以直接return false。如果大于,那么可以直接分。
此时要注意,因为我们二分是从后往前处理,所以我们的当前石子堆的数量已经被后面的给了一部分,也就是大于原来的,我们能给的数量最大就是当前堆-k。但是题目要求是从前往后处理,你吧这一堆分给前面两个,此时这一堆还未被后面的给与,所以分的最大值就是原始堆的数量。**res=min(b[i]-mid,a[i])**就是这样来的。

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long int ll;
const int N = 2e5+5;
int n;
ll a[N],b[N];

bool check(ll mid){
	for(int i=1;i<=n;i++)
		b[i]=a[i];
	
	for(int i=n;i>=3;i--){
		if(b[i]<mid) return false;
		ll res=(b[i]-mid)/3;
		res=min(res,a[i]/3);//最大不能超过1/3
		b[i]-=res*3;
		b[i-1]+=res;
		b[i-2]+=res*2;
	}
	return b[1]>=mid&&b[2]>=mid;
	
}
//每一次挪的时候 还没有被后面石头增加
//所以 判断一下 res = min(b[i]-mid,a[i])/3
void solve(){
	mem(a,0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	ll l=0,r=INT_MAX;
	while(l<=r){
		ll mid = (l+r+1)/2;
		if(check(mid)) l=mid+1;
		else r=mid-1;
	}
	cout<<l-1<<endl;
}


int main(){
	ios::sync_with_stdio(false);
	int t;cin>>t;
	while(t--)
	solve();	
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值