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;
}