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;
}