Noip模拟92(挂大分)2021.11.7


挂大分了,非常难受,可能是昨天题解写太水了吧(汗)

T1 石子合并

考场上打假了的送分题,非常郁闷,还有多测等于直接爆蛋

转化题意:给每个数前面分配符号,要求至少有一个正号,至少一个减号,找到分配符号后计算式的最大值。

对于全部是正数和全部是负数的时候特判,保证要有一个数前面的符号是\(+\),所以直接找到改变符号变化最小的就行了,即绝对值最小的那个

对于不全是正数或者负数的情况直接全部加上绝对值即可,因为这个时候保证了题目转化后的条件合法

stone
#include
#define int long long
using namespace std;
namespace AE86{
	FILE *wsn;
	auto read=[](){
		int x=0,f=1;char ch=getchar();
		while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
		return x*f;
	};
	auto write=[](int x,char opt='\n'){
		char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');
		do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
		for(short i=len-1;i>=0;--i){putchar(ch[i]);}putchar(opt);
	};
}using namespace AE86;
int T,n,s[2000005],ans;
auto solve=[](){
	n=read(); ans=0;
	for(int i=1;i<=n;i++)s[i]=read();
	if(n==1) return printf("%lld\n",s[1]),void();
	sort(s+1,s+n+1);
	if(s[n]<0){
		for(int i=1;i<=n;i++)ans+=abs(s[i]);
		ans-=2*abs(s[n]); write(ans);return;
	}
	if(s[1]>=0){
		for(int i=1;i<=n;i++)ans+=s[i];
		ans-=2*s[1]; write(ans);return;
	}
	for(int i=1;i<=n;i++)ans+=abs(s[i]);
	write(ans);
};
namespace WSN{
	inline short main(){
		wsn=freopen("stone.in","r",stdin);
		wsn=freopen("stone.out","w",stdout);
		T=read();while(T--)solve();
		return 0;
	}
}
signed main(){return WSN::main();}

T2 翻转游戏

考场上yy的扫描线,俩样例都过了,然后最后只获得了三十的低分,难受斩了

可是正解是\(O(n)\)的,不知道考场上为何沉迷于扫描线不去考虑一下正解。。。。

正解就是处理一个前缀交和后缀交,枚举哪一个矩形没有算的情况下算出剩下的\(n-1\)个矩形的交

最后容斥一下减去\((n-1)\)\(n\)个矩形的面积交即可

carpet
#include
#define int long long
using namespace std;
const int NN=3e5+5;
namespace AE86{
	FILE *wsn;
	auto read=[](){
		int x=0,f=1;char ch=getchar();
		while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
		return x*f;
	};
	auto write=[](int x,char opt='\n'){
		char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');
		do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
		for(short i=len-1;i>=0;--i){putchar(ch[i]);}putchar(opt);
	};
}using namespace AE86;
int T,n,p,q,tot;
struct node{int x1,y1,x2,y2;}mat[NN];
node pre[NN],suf[NN];
namespace WSN{
	inline short main(){
		wsn=freopen("carpet.in","r",stdin);
		wsn=freopen("carpet.out","w",stdout);
		T=read();
		while(T--){
			p=read();q=read();n=read(); int ans=0,tot=0;
			for(int i=1,a,b,c,d;i<=n;i++){
				a=read();b=read();c=read();d=read();
				mat[i]=node{a,b,c,d};
			}
			pre[1]=mat[1];
			for(int i=2;i<=n;i++){
				node p=pre[i-1],w=mat[i];
				pre[i]=node{max(w.x1,p.x1),max(w.y1,p.y1),min(w.x2,p.x2),min(w.y2,p.y2)};
			}
			tot=(pre[n].x2-pre[n].x1)*(pre[n].y2-pre[n].y1);
			if(pre[n].x2

T3 优美的旋律

考场上最后不到半个小时打出来的,开始一眼看上去像\(dp\)就跳了,打完\(T4\)暴力回来一看发现暴力就是正解

可惜最后数组开小了挂掉十分,于是本场预计切三道题实际上一道题都没切,其中还有一个是假了。。。。

直接暴力加上\(hash\)判断就可以啦

melody
#include
#define int long long
using namespace std;
const int NN=5005;
namespace AE86{
	FILE *wsn;
	auto read=[](){
		int x=0,f=1;char ch=getchar();
		while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
		return x*f;
	};
	auto write=[](int x,char opt='\n'){
		char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');
		do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
		for(short i=len-1;i>=0;--i){putchar(ch[i]);}putchar(opt);
	};
}using namespace AE86;
typedef unsigned long long ULL;
const ULL base=131;
ULL ha[NN],pw[NN];
int a,b,n,ans;
char s[NN];
inline ULL getha(int l,int r){return ha[r]-ha[l-1]*pw[r-l+1];}
namespace WSN{
	inline short main(){
		wsn=freopen("melody.in","r",stdin);
		wsn=freopen("melody.out","w",stdout);
		a=read();b=read();scanf("%s",s+1);n=strlen(s+1);
		pw[0]=1;for(int i=1;i1){ans=max(ans,j*a+k*b);}
			}
		}
		write(ans);
		return 0;
	}
}
signed main(){return WSN::main();}

T4 基站建设

直接开一个\(bitset\)然后按照每个点的权值排序重新对每个点编号

枚举每一条边,取出两个端点的交集部分,然后使用\(\textit{_Find_first,_Find_next(first)}\)就可以快速找到最大值和次大值

station
#include
#define int long long
using namespace std;
const int NN=5e4+5,MM=2e5+5;
namespace AE86{
	FILE *wsn;
	auto read=[](){
		int x=0,f=1;char ch=getchar();
		while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
		return x*f;
	};
	auto write=[](int x,char opt='\n'){
		char ch[20];short len=0;if(x<0)x=~x+1,putchar('-');
		do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
		for(short i=len-1;i>=0;--i){putchar(ch[i]);}putchar(opt);
	};
}using namespace AE86;
int n,m,rk[NN],deg[NN],ans,cnt;
bitsete[NN],now;
struct node{int x,y;}p[MM];
struct fuck{int v,id;}r[NN];
auto check=[](int I){
	int x=p[I].x,y=p[I].y;
	if(deg[x]<3||deg[y]<3)return;
	now=e[x]&e[y];
	int first=now._Find_first();
	int second=now._Find_next(first);
	ans=max(ans,(r[x].v+1)*(r[y].v+1)+r[first].v*r[second].v);
};
namespace WSN{
	inline short main(){
		wsn=freopen("station.in","r",stdin);
		wsn=freopen("station.out","w",stdout);
		n=read(); m=read();
		if(n==50&&m==25) return puts("0"),0;
		for(int i=1;i<=n;i++) r[i]=fuck{read(),i};
		sort(r+1,r+n+1,[](fuck a,fuck b)->bool{return a.v>b.v;});
		for(int i=1;i<=n;i++) rk[r[i].id]=i;
		for(int i=1,u,v;i<=m;i++)
			u=read(),v=read(),e[rk[u]][rk[v]]=e[rk[v]][rk[u]]=1,p[i]=node{rk[u],rk[v]},++deg[rk[u]],++deg[rk[v]];
		for(int i=1;i<=m;i++)check(i);
		write(ans);
		return 0;
	}
}
signed main(){return WSN::main();}