CSP-S开小灶5

感觉自己 \(rp\) 要提前爆完了,千万别啊

A. 乌鸦喝水

暴力链表 \(95pts\)

其实有这样一个性质,转换为每个桶最多被喝多少次以后,次数小的桶一定先被喝完

于是按照次数排序,每次处理一个桶即可

考场上没有推出前面的性质,所以有一个线段树思路,就是每个点减去他前面还剩下的元素个数,每次找最小值,但是由于对复杂度分析错误了很久,最后才发现复杂度是正确的,所有完全没有时间实现

所以对复杂度的分析能力有待提升

code
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
ll read(){
	ll x = 0; char c = getchar();
	while(c < '0' || c > '9')c = getchar();
	do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
	return x;
}
const int maxn = 100005;
ll n, m, x, w[maxn];
struct node{
	ll a, pos;
	friend bool operator < (const node &x, const node &y){
		return x.a == y.a ? x.pos > y.pos : x.a < y.a;
	}
}a[maxn];
struct BIT{
	int t[maxn];
	int lowbit(int x){return x & -x;}
	void add(int x){
		while(x <= n){
			++t[x];
			x += lowbit(x);
		}
	}
	int query(int x){
		int ans = 0;
		while(x){
			ans += t[x];
			x -= lowbit(x);
		}
		return ans;
	}
}t;
int main(){
	n = read(), m = read(), x = read();
	for(int i = 1; i <= n; ++i)w[i] = read();
	for(int i = 1; i <= n; ++i)a[i].a = read();
	for(int i = 1; i <= n; ++i)a[i].a = max(0ll, (x - w[i] + a[i].a) / a[i].a), a[i].pos = i;
	sort(a + 1, a + n + 1);
	ll ans = 0, p = 1, npos = 1, res = n;
	for(int round = 1; round <= m; ){
		while(p <= n && a[p].a <= ans){
			if(a[p].pos - t.query(a[p].pos) < npos) --npos;
			t.add(a[p].pos);
			--res; ++p;
		}
		if(p > n)break;
		ll tmp = npos + a[p].a - ans;
		if(round + (tmp - 1) / res > m){
			ans += (m - round) * res + res - npos + 1;
			break;
		}
		ans += a[p].a - ans;
		round += (tmp - 1) / res;
		tmp %= res;
		npos = tmp ? tmp : res;
	}
	printf("%lld\n",ans);
	return 0;
}

B. kill

做法正确,但是没有排序?

但是有 \(80pts\)

昨天讲错了,其实不用那么麻烦

考虑两个人 \(pos_a < pos_b\) ,那么他们对应打的怪物的位置必然有 \(p_a < p_b\) 否则交换他们一定更优

于是二分答案扫一遍 \(check\) 一下即可

code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read(){
	int x = 0; char c = getchar();
	while(c < '0' || c > '9')c = getchar();
	do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
	return x; 
}
const int maxn = 10005;
int n, m, s, p[maxn], q[maxn], ps;
bool vis[maxn];
bool check(int mid){
	for(int i = 1; i <= m; ++i)vis[i] = 0;
	int p1 = 1;
	for(int i = 1; i <= n; ++i){
		while((vis[p1] || abs(q[p1] - p[i]) + abs(q[p1] - s) > mid) && p1 <= m) ++p1;
		if(vis[p1] || p1 > m)return false;
		vis[p1] = 1;
	}
	return true;
}
signed main(){
	n = read(), m = read(), s = read();
	for(int i = 1; i <= n; ++i)p[i] = read();
	for(int i = 1; i <= m; ++i)q[i] = read();
	sort(p + 1, p + n + 1); sort(q + 1, q + m + 1);
	int l = 0, r = 0;
	for(int i = 1; i <= n; ++i)r = max(0 + abs(q[i] - p[i]) + abs(q[i] - s), r);
	int ans = r;
	while(l <= r){
		int mid = (l + r) >> 1;
		if(check(mid))ans = mid, r = mid - 1;
		else l = mid + 1;
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2022-09-17 09:48  Chen_jr  阅读(44)  评论(2编辑  收藏  举报