NOIP2024 前集训:多校A层冲刺NOIP2024模拟赛20

前言

image

考古了,现在才写。

已经忘了赛时历程了,就记得 T1 打了个错误率高达 \(\dfrac{1}{100000}\) 的乱搞做法(前后各连 \(\log\)\(k\) 大值)然后被卡常了,后三道都没交不记得为啥了。

T1 星际联邦

std 是 \(O(m\log m)\) 的菠萝算法,但是被众人疯狂爆标。

正解是 \(O(n)\) 的,不考虑连通性的话每个点连前缀最大值或后缀最小值是最优的,考虑连通性,他只能去连接第一个大于他的位置以后的后缀最小值,其实就是先分组,再组间连边,正确性是保证的。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=3e5+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,m,a[N],f[N],e[N],mn[N]; ll ans;
inline int find(int x) {return x==f[x]?x:f[x]=find(f[x]);}
signed main()
{
	freopen("star.in","r",stdin),freopen("star.out","w",stdout);
	read(n),a[0]=-1e9; for(int i=1,x=0;i<=n;i++)
		read(a[i]),f[i]=i,a[x]<a[i]?e[++m]=x=i:f[find(i)]=x;
	mn[n+1]=1e9; for(int i=n;i;i--) mn[i]=min(mn[i+1],a[i]);
	for(int i=1,x;i<=n;i++) if(i!=(x=find(i))) ans+=min(a[i]-a[x],mn[i+1]-a[i]);
	for(int i=1;i<m;i++) ans+=mn[e[i+1]]-a[e[i]]; write(ans);
}

T2 和平精英

首先需要知道一些性质:

  • \(x\&y\le \min(x,y),x|y\ge \max(x,y)\)
  • \(popcount(x\&y)\le \min(popcount(x),popcount(y)),popcount(x|y)\ge \max(popcount(x),popcount(y))\)

针对第一个性质我们有了 \(O(q(n+v))\) 的枚举答案的做法,这是扯淡的,半分都没有。

针对第二个性质我们有了 \(O(q(n+\log v))\) 的做法,这已经是一个优秀的暴力了。

即对于每个枚举的 \(p\),若 \(popcount(a_i)<p\) 则扔到 \(\{或\}\) 里,若 \(popcount(a_i)>p\) 则扔到 \(\{与\}\) 里,否则对于 \(\{a_i\mid popcount(a_i)=p\}\) 的,发现他们应该全部相等,然后再丢到哪个里面就无所谓了,两边可以抵消掉。

然后发现只要加个线段树就可以通过此题,每个 \(ppcount\) 开一颗线段树,维护区间或、与以及数的个数即可,复杂度 \(O(n\log n\log v)\)

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
#define mid (l+r>>1)
#define ls (mid<<1)
#define rs (mid<<1|1)
using namespace std;
const int N=1e5+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,m,a[N];
struct aa
{
	int oor,aand=(1<<30)-1,cnt;
	inline aa operator + (const aa a) const
	{return (aa){oor|a.oor,aand&a.aand,cnt+a.cnt};}
};
class segment_tree
{
	private:
		aa t[N<<1];
		inline int count(int x,int res=0)
		{for(int i=0;i<=30;i++) res+=(x>>i)&1; return res;}
	public:
		inline void build(int p,int l,int r,int d)
		{
			if(l==r)
			{
				if(count(a[l])==d) t[p].cnt=1,t[p].oor=t[p].aand=a[l];
				return ;
			}
			build(ls,l,mid,d),build(rs,mid+1,r,d),t[p]=t[ls]+t[rs];
		}
		inline aa ask(int p,int l,int r,int vl,int vr)
		{
			if(vl<=l&&vr>=r) return t[p];
			if(vr<=mid) return ask(ls,l,mid,vl,vr);
			if(vl>mid) return ask(rs,mid+1,r,vl,vr);
			return ask(ls,l,mid,vl,vr)+ask(rs,mid+1,r,vl,vr);
		}
}T[35];
signed main()
{
	freopen("peace.in","r",stdin),freopen("peace.out","w",stdout);
	read(n,m);
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=0;i<=30;i++) T[i].build(1,1,n,i);
	for(int l,r;m;m--)
	{
		read(l,r); aa pos[35],pre[35],suf[35]; bool flag=0;
		for(int i=0;i<=30;i++) pos[i]=pre[i]=suf[i]=T[i].ask(1,1,n,l,r);
		for(int i=1;i<=30;i++) pre[i]=pre[i-1]+pos[i];
		for(int i=29;~i;i--) suf[i]=suf[i+1]+pos[i];
		for(int i=0;i<=29;i++) flag|=(pre[i].cnt&&suf[i+1].cnt&&pre[i].oor==suf[i+1].aand);
		for(int i=0;i<=30;i++) flag|=(pos[i].cnt>1&&pos[i].oor==pos[i].aand&&pre[i].oor==suf[i].aand);
		puts(flag?"YES":"NO");
	}
}

T3 摆烂合唱

需要知道什么是表达式树,然后就没有然后了,\(f_{x,0/1}\) 表示 \(x\)\(0/1\) 概率,显然这两个概率加起来为 \(1\)

  • 异或:\(f_{x,0}=f_{ls,0}\times f_{rs,0}+f_{ls,1}\times f_{rs,1},f_{x,1}=1-f_{x,0}\)
  • 或:\(f_{x,0}=f_{ls,0}\times f_{rs,0},f_{x,1}=1-f_{x,0}\)
  • 与:\(f_{x,1}=f_{ls,1}\times f_{rs,1},f_{x,0}=1-f_{x,1}\)

然后再遍历一遍输出即可:

  • 异或:不管相邻项选什么此时填 \(0/1\) 答案都不同。
  • 或:相邻项选 \(0\),则此时填 \(0/1\) 答案不同。
  • 与:相邻项选 \(1\),则此时填 \(0/1\) 答案不同。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=4e5+10,P=998244353,inv=499122177;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,pos,tot,ls[N],rs[N],f[N][2]; char s[N],t[N];
inline int mod(int x,int y) {return (x+=y)>=P?x-P:x;}
inline int dfs()
{
	int x=++tot; if(s[++pos]=='x') return t[x]='x',f[x][0]=f[x][1]=inv,x;
	ls[x]=dfs(),t[x]=s[++pos],rs[x]=dfs(),pos++;
	switch(t[x])
	{
		case '^':
			f[x][0]=mod(1ll*f[ls[x]][0]*f[rs[x]][0]%P,1ll*f[ls[x]][1]*f[rs[x]][1]%P);
			f[x][1]=P+1-f[x][0]; break;
		case '|':
			f[x][0]=1ll*f[ls[x]][0]*f[rs[x]][0]%P;
			f[x][1]=P+1-f[x][0]; break;
		case '&':
			f[x][1]=1ll*f[ls[x]][1]*f[rs[x]][1]%P;
			f[x][0]=P+1-f[x][1]; break;
	}
	return x;
}
inline void print(int x,int ans)
{
	if(t[x]=='x') return write(ans),puts(""),void();
	switch(t[x])
	{
		case '^': print(ls[x],ans),print(rs[x],ans); break;
		case '|':
			print(ls[x],1ll*ans*f[rs[x]][0]%P);
			print(rs[x],1ll*ans*f[ls[x]][0]%P); break;
		case '&':
			print(ls[x],1ll*ans*f[rs[x]][1]%P);
			print(rs[x],1ll*ans*f[ls[x]][1]%P); break;
	}
}
signed main()
{
	freopen("binary.in","r",stdin),freopen("binary.out","w",stdout);
	read(n),scanf("%s",s+1),dfs(),print(1,1);
}

T4 对称旅行者

有这题?

posted @ 2024-11-13 11:52  卡布叻_周深  阅读(36)  评论(1编辑  收藏  举报