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

  • 线段树,枚举每一次第一个发出信号的点;

C.rain

posted @ 2022-08-09 19:02  Star_LIcsAy  阅读(20)  评论(0)    收藏  举报