2021.10.15考试总结[NOIP模拟77]

\(n=40\)考虑\(meet \;in \;the \;middle\)

某个元素有关的量只有一个时考虑转化为树上问题

对暴力有自信,相信数据有梯度

没了

UPD:写了个略说人话的。

T1 最大或

选两个数,其中一个肯定选\(r\)。另一个在不卡上界后二进制位全选\(1\)

\(code:\)

T1
#include<bits/stdc++.h>
#define int long long
using namespace std;

namespace IO{
	typedef long long LL;
	auto read=[]()->int{
		char ch=getchar(); int x=0,f=1;
		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=[](LL x,int sp)->void{
		char ch[20]; int len=0;
		if(x<0){ x=~x+1; putchar('-'); }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	};
	auto ckmax=[](int& x,int y)->void{ x=x<y?y:x; };
	auto ckmin=[](int& x,int y)->void{ x=x<y?x:y; };
} using namespace IO;

const int NN=70;
int t,l,r,ll,rr,ans;
int bitl[NN],bitr[NN];
bool up;

signed main(){
	freopen("maxor.in","r",stdin);
	freopen("maxor.out","w",stdout);
	t=read();
	while(t--){
		memset(bitl,0,sizeof(bitl));
		memset(bitr,0,sizeof(bitr));
		l=read(); r=read(); ans=r; up=1;
		ll=log2(l)+1; rr=log2(r)+1;
		for(int i=l,p=1;i;i>>=1,++p) bitl[p]=i&1;
		for(int i=r,p=1;i;i>>=1,++p) bitr[p]=i&1;
		for(int i=rr;i;i--){
			if(bitr[i]&&!bitl[i]) up=0;
			if(up) continue;
			if(!bitr[i]) ans+=1ll<<i-1;
		}
		write(ans,'\n');
	}
	return 0;
}

T2 答题

这种范围奇怪且好像只会\(2^n\)暴力的题,一般有个惯用套路\(meet\;in\;the\;middle\)

这种直接写不好写且答案单调的题,一般有个惯用套路二分答案。

于是\(meet\;in\;the\;middle\)后二分答案,要求的其实是选出小于\(mid\)的分数的方案数。双指针扫一遍即可。

\(code:\)

T2
#include<bits/stdc++.h>
#define int long long
using namespace std;

namespace IO{
	typedef long long LL;
	typedef double DB;
	auto read=[]()->int{
		char ch=getchar(); int x=0,f=1;
		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=[](LL x,int sp)->void{
		char ch[20]; int len=0;
		if(x<0){ x=~x+1; putchar('-'); }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	};
	auto ckmax=[](int& x,int y)->void{ x=x<y?y:x; };
	auto ckmin=[](int& x,int y)->void{ x=x<y?x:y; };
} using namespace IO;

const int NN=50;
int n,l,r,sum,res,pts[NN];
int cntl,cntr,lf[1050000],rt[1050000];
DB p;

bool check(int mid){
	int tmp=rt[0],cnt=0;
	for(int i=1;i<=lf[0];i++){
		if(lf[i]>mid) break;
		while(tmp&&rt[tmp]+lf[i]>mid) --tmp;
		cnt+=tmp;
	}
	return p<=cnt;
}

signed main(){
	freopen("answer.in","r",stdin);
	freopen("answer.out","w",stdout);
	n=read(); scanf("%lf",&p); p=ceil(p*(1ll<<n));
	for(int i=1;i<=n;i++) pts[i]=read(), r+=pts[i];
	cntl=(n+1)>>1; cntr=n>>1;
	for(int i=0;i<(1<<cntl);i++){
		++lf[0];
		for(int j=0;j<cntl;j++) if(i&(1<<j))
			lf[lf[0]]+=pts[j+1];
	}
	for(int i=0;i<(1<<cntr);i++){
		++rt[0];
		for(int j=0;j<cntr;j++) if(i&(1<<j))
			rt[rt[0]]+=pts[j+cntl+1];
	}
	sort(lf+1,lf+lf[0]+1);
	sort(rt+1,rt+rt[0]+1);
	while(l<=r){
		int mid=l+r>>1;
		if(check(mid)) r=mid-1,res=mid;
		else l=mid+1;
	}
	write(res,'\n');
	return 0;
}
/*
4 0.01
4
2
4
2

*/

T3 联合权值

暴力直接过极限数据,有点不懂。

T4 主仆见证了hobo的离别

每个元件只被融合一次,考虑将这种关系建出一棵树,由原来的元件做新合成元件的儿子。

每次询问时,如果\(x,y\)没有祖先关系,则无解。否则,如果\(x\)\(y\)的祖先,则\(y\)\(x\)路径上需全是交,反之全是并。用并查集维护每个点向上延伸交并的最小深度即可。注意\(k=1\)时交并等价。

\(code:\)

T4
#include<bits/stdc++.h>
using namespace std;

namespace IO{
	typedef long long LL;
	auto read=[]()->int{
		char ch=getchar(); int x=0,f=1;
		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=[](LL x,int sp)->void{
		char ch[20]; int len=0;
		if(x<0){ x=~x+1; putchar('-'); }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	};
	auto ckmax=[](int& x,int y)->void{ x=x<y?y:x; };
	auto ckmin=[](int& x,int y)->void{ x=x<y?x:y; };
} using namespace IO;

const int NN=500010;
int n,m,x,y,k,tp,op,num,tot;
int cnt,f[NN],fa[NN],fo[NN],dep[NN],siz[NN],dfn[NN];
int idx,to[NN],nex[NN],head[NN];
struct query{ int x,y; }q[NN];
int geta(int a){ return fa[a]==a?a:fa[a]=geta(fa[a]); }
int geto(int o){ return fo[o]==o?o:fo[o]=geto(fo[o]); }
void add(int a,int b){
	to[++idx]=b; nex[idx]=head[a]; head[a]=idx; f[b]=a;
}

void dfs(int s,int ff){
	siz[s]=1; dep[s]=dep[ff]+1; dfn[s]=++cnt;
	for(int i=head[s];i;i=nex[i])
		dfs(to[i],s),siz[s]+=siz[to[i]];
}

signed main(){
	freopen("friendship.in","r",stdin);
	freopen("friendship.out","w",stdout);
	n=read(); m=read(); tot=n;
	for(int i=1;i<=n+m;i++) fa[i]=fo[i]=i;
	for(int i=1;i<=m;i++){
		tp=read();
		if(!tp){
			op=read(); k=read(); ++tot;
			for(int a,i=1;i<=k;i++){
				a=read(),add(tot,a),op?fo[geto(a)]=tot:fa[geta(a)]=tot;
				if(k==1) op?fa[geta(a)]=tot:fo[geto(a)]=tot;
			}
		} else q[++num].x=read(),q[num].y=read();
	}
	for(int i=1;i<=tot;i++) if(!f[i]) dfs(i,0);
	for(int i=1;i<=num;i++)
		if(dep[q[i].x]>dep[q[i].y]){
			if(dfn[q[i].x]<dfn[q[i].y]){ puts("0"); continue; }
			if(dfn[q[i].x]>=dfn[q[i].y]+siz[q[i].y]){ puts("0"); continue; }
			if(dep[geto(q[i].x)]>dep[q[i].y]){ puts("0"); continue; }
			puts("1");
		} else{
			if(dfn[q[i].y]<dfn[q[i].x]){ puts("0"); continue; }
			if(dfn[q[i].y]>=dfn[q[i].x]+siz[q[i].x]){ puts("0"); continue; }
			if(dep[geta(q[i].y)]>dep[q[i].x]){ puts("0"); continue; }
			puts("1");
		}
	return 0;
}
posted @ 2021-10-15 21:42  keen_z  阅读(52)  评论(1编辑  收藏  举报