2022/8/9 总结
题单:这里
A.Wave
Solution
-
对于每一个 \(01\) 小段,统计 \(3\) 个数字:
- 作为前半段的贡献,也就是只有 \(0\) 会产生贡献;
- 作为后半段的贡献,也就是只有 \(1\) 会产生贡献;
- 作为分界点的那一段的贡献,即前半段 \(0\) 产生贡献,后半段 \(1\) 产生贡献,这个需要另外枚举段中分界点;
-
先统计一个初步 \(Ans\),每扫过一个小段就加入它不作为分界点的最大贡献,然后再扫一遍,统计每个点作为分界点的最大贡献(因为分界点至多只有一个);
AC code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int s=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
s=s*10+int(ch-'0');
ch=getchar();
}
return s*f;
}
const int N=5e5+10;
int n;
int m[N];
int f[N][3];
int c[N];
void add(int x,int y,int M){
for(;x<=M;x+=x&-x)
c[x]+=y;
return ;
}
int ask(int x){
int cnt=0;
for(;x;x-=x&-x)
cnt+=c[x];
return cnt;
}
int main(){
// freopen("wave.in","r",stdin);
// freopen("wave.out","w",stdout);
n=read();
int p=0,ans=0;
for(int i=1;i<=n;++i){
m[i]=read();
fill(c+1,c+m[i]+1,0);
string s;
int a;
for(int j=1;j<=m[i];++j){
a=read();
++f[i][a];
add(j,a,m[i]);
}
for(int j=2;j<=m[i];++j)
f[i][2]=max(f[i][2],j-ask(j)+ask(m[i])-ask(j-1));
if(f[i][0]>f[i][1])
p+=f[i][0];
else p+=f[i][1];
}
ans=p;
for(int i=1;i<=n;++i)
ans=max(ans,p-max(f[i][0],f[i][1])+f[i][2]);
printf("%d",ans);
return 0;
}
B.scientist
Solution
- 线段树,枚举每一次第一个发出信号的点;