E. Nezzar and Binary String
题意:
两个(01)串(s),(f),(q)个询问区间,每次询问之后可以修改询问的区间内不超过一半的字符,问能否做到每次询问的区间内字符相同(全(1)或全(0))并且所有询问结束后(s)与(f)相同
思路:
倒着做,线段树维护区间赋值
#include<bits/stdc++.h>
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
typedef long long ll;
const int maxn = 200010;
char s[maxn], f[maxn];
int l[maxn], r[maxn];
int sum[maxn << 2], lazy[maxn << 2];
void pushUp(int rt){
sum[rt] = sum[ls] + sum[rs];
}
void build(int rt, int l, int r){
lazy[rt] = -1;
if(l==r){
sum[rt] = f[l]-'0';
return ;
}
int mid = (l + r) >> 1;
build(ls,l,mid);
build(rs,mid+1,r);
pushUp(rt);
}
void pushDown(int rt, int l, int r){
if(lazy[rt]!=-1){
lazy[ls] = lazy[rs] = lazy[rt];
int mid = (l + r) >> 1;
sum[ls] = lazy[ls] * (mid - l + 1);
sum[rs] = lazy[rs] * (r - mid);
lazy[rt] = -1;
}
}
void update(int rt, int l, int r, int p, int L, int R){
if(L<=l&&r<=R){
sum[rt] = (r - l + 1) * p;
lazy[rt] = p;
return ;
}
pushDown(rt, l, r);
int mid = (l + r) >> 1;
if(mid >= L)
update(ls, l, mid, p, L, R);
if(mid < R)
update(rs, mid + 1, r, p, L, R);
pushUp(rt);
}
int query(int rt, int l, int r, int L, int R){
if(L<=l&&r<=R)return sum[rt];
pushDown(rt, l, r);
int mid = (l + r) >> 1, ans = 0;
if(mid >= L)
ans += query(ls, l, mid, L, R);
if(mid < R)
ans += query(rs, mid + 1, r, L, R);
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t, n, q;
cin >> t;
while(t--) {
cin>> n >> q >> (s+1) >> (f+1);
for(int i = 0; i < q; i++) cin >> l[i] >> r[i];
reverse(l, l + q);
reverse(r, r + q);
build(1, 1, n);
int flag = 0;
for(int i = 0; i < q; i++) {
int res = query(1, 1, n, l[i], r[i]);
if((r[i] - l[i] + 1) % 2 == 0 && res == (r[i] - l[i] + 1) / 2){
flag = 1;
break;
}
if(res <= (r[i] - l[i] + 1) / 2)update(1, 1, n, 0, l[i], r[i]);
else update(1, 1, n, 1, l[i], r[i]);
}
if(flag) cout << "NO
";
else {
int sl = 1, sr = 1;
while(sr <= n){
while(s[sl] == s[sr]) sr++;
int res = query(1, 1, n, sl, sr - 1);
if(s[sl] == '0' && res != 0){
flag = 1;
break;
}
if(s[sl] == '1' && res != sr - sl){
flag = 1;
break;
}
sl = sr;
}
if(flag) cout << "NO
";
else cout<<"YES
";
}
}
return 0;
}
F. Nezzar and Nice Beatmap
题意:
(n)个点,重新排序使得任意三个连续的点形成的角(以中间的点为顶点)小于(90)度
思路:
任意选择一个点为起点,每次选择离该点最远的点作为下一个点,以此类推。假设第一个点为(a),第二个点为(b),则剩余的所有点在以(a)为圆心,(b)为半径的圆内,且(b)在圆上,则与下一个点形成的角一定小于(90)度
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5010;
int vis[maxn], x[maxn], y[maxn];
ll dis2(int a, int b) {
return (ll)(x[a] - x[b]) * (x[a] - x[b]) + (ll)(y[a] - y[b]) * (y[a] - y[b]);
}
vector<int> ans;
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) cin >> x[i] >> y[i];
int now = 0, m = n - 1;
ans.push_back(now);
vis[now] = 1;
while (m--) {
ll len = 0;
int k = -1;
for (int j = 0; j < n; j++) {
if (vis[j] == 0 && dis2(now, j) > len) {
len = dis2(now, j);
k = j;
}
}
vis[k] = 1;
now = k;
ans.push_back(now);
}
for (auto i : ans) printf("%d ", i + 1);
puts("");
return 0;
}