ABC408
D
link

首先考虑比较暴力的怎么做。
我们考虑一个前缀和的数组\(qzh_{0/1,i}\)代表\(1\)~\(i\)中\(0/1\)的个数。
那么如果我们让区间\(l\)~\(r\)(因为区间长度可以为\(0\),所以\(r \geq l-1\))是\(1\),答案就是\(qzh_{1,l-1}+(qzh_{1,n}-qzh_{1,r})+(qzh_{0,r}-qzh_{0,l-1})\)。
我们拆一下这个式子:\(qzh_{1,n}+(qzh_{1,l-1}-qzh_{0,l-1})+(qzh_{0,r}-qzh_{1,r})\)。
其中,\(qzh_{1,n}\)是固定的,那么我们枚举\(l\),找到所有\(i \geq l-1\)中最小的\(qzh_{0,i}-qzh_{1,i}\),找最小做一个后缀最小值即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
string s;
int q[2][200005];
int c[200005];
void solve(){
cin >> n >> s;
for(int i = 1;i <= n;++ i){
q[1][i] = q[1][i-1];
q[0][i] = q[0][i-1];
if(s[i-1] == '1') q[1][i]++;
else q[0][i]++;
c[i] = q[0][i]-q[1][i];
}
int ans = 1e9;
int res = c[n];
for(int i = n;i >= 1;-- i){
res = min(res,c[i-1]);
ans = min(ans,q[1][i-1]-q[0][i-1]+res);
}
cout << ans+q[1][n] << endl;
}
signed main(){
int _;cin >> _;
while(_--) solve();
return 0;
}
E
link

考虑贪心。
从高位到底位枚举每一个二进制位,考虑如果只走这一位是\(0\)的边能不能走到终点。
如果能,那么枚举后面的时候这一位也一定要是\(0\),否则枚举后面的时候这一位随意。那么如何实现这个呢,用一个变量(代码中是\(s\)),判断能不能走这个边的时候就拿边权和\(s\)做\(&\),如果是\(0\)就可以走。这时,如果后面一定要是\(0\),那么把\(s\)的这一位设成\(1\),这样后面只有是\(0\)才能使最终结果是\(0\);如果后面随意,那么这一位是\(0\),这样后边不管是什么都可以变成\(0\)。
如何判断能否走到终点?并查集。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
struct edge{
int u,v,w;
}a[200005];
int ans;
int fa[200005];
int find(int x){
if(x == fa[x]) return x;
else return fa[x] = find(fa[x]);
}
void merge(int x,int y){
fa[find(x)] = find(y);
}
signed main(){
cin >> n >> m;
for(int i = 1;i <= m;++ i)
cin >> a[i].u >> a[i].v >> a[i].w;
int s = 0;
for(int i = 29;i >= 0;-- i){
s += (1<<i);
for(int j = 1;j <= n;++ j) fa[j] = j;
for(int j = 1;j <= m;++ j)
if(!(a[j].w&s)) merge(a[j].u,a[j].v);
if(find(1) != find(n))
s -= (1<<i),ans += (1<<i);
}
cout << ans;
return 0;
}
F
link

设\(f_i\)代表从高度为\(i\)的木桩出发最多能走多少步。下文中\(wz_i\)代表高度为\(i\)的木桩的位置。
那么有转移:\(f_i = max(f_j)+1\)其中\(j\)要满足\(i-r \leq wz_j \leq i+r\)且\(j \leq i-d\)
第一个条件好说,区间求\(max\),可以用线段树,把所有\(f_i\)加到\(wz_i\)这个位置上,第二个条件就没有那么简单了。
我们按高度从小到大求\(f\),那么我们每次只把高度在\(1\)~\(i-d\)中的加到序列上即可,然后再区间求\(max\)。
最终答案是所有的\(f\)取\(max\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define ls x*2
#define rs x*2+1
using namespace std;
int n,D,R;
int a[500005];
int wz[500005];
int f[500005];
int val[2000005];
void update(int x){
val[x] = max(val[ls],val[rs]);
}
void change(int x,int l,int r,int k,int s){
if(l == r){
val[x] = s;
return;
}
int mid = (l+r)/2;
if(k <= mid) change(ls,l,mid,k,s);
else change(rs,mid+1,r,k,s);
update(x);
}
int query(int x,int l,int r,int lx,int rx){
if(lx <= l&&r <= rx) return val[x];
int mid = (l+r)/2,ans = -1;
if(lx <= mid) ans = max(ans,query(ls,l,mid,lx,rx));
if(rx > mid) ans = max(ans,query(rs,mid+1,r,lx,rx));
return ans;
}
signed main(){
memset(val,-1,sizeof(val));
cin >> n >> D >> R;
for(int i = 1;i <= n;++ i)
cin >> a[i],wz[a[i]] = i;
int ans = 0;
for(int i = 1;i <= n;++ i){
if(i-D > 0) change(1,1,n,wz[i-D],f[i-D]);
f[i] = query(1,1,n,max(1ll,wz[i]-R),min(n,wz[i]+R))+1;
ans = max(ans,f[i]);
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号