把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

Public NOIP Round #1 (Div. 1, 提高)

斜二等轴测图

模拟即可。

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=100+5,M=13,M1=pow(3,13),M2=28,K=1e5+5,mod=998244353,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;
int a,b,c,n,m;char S[N][N];
void Solve(){
	int i,j;scanf("%d%d%d",&a,&b,&c);n=1+2*(b+c);m=1+2*(a+b);for(i=1;i<=n;i++) for(j=1;j<=m;j++)S[i][j]='.';
	for(i=1;i<=a+1;i++) for(j=1;j<=c+1;j++) S[n-2*j+2][2*i-1]='+';
	for(i=1;i<=b;i++) {for(j=1;j<=a+1;j++) S[2*i-1][m-2*j+2-2*i+2]='+',S[2*i][m-2*j+2-2*i+1]='/';
	for(j=1;j<=c+1;j++) S[2*j-1+2*i-2][m-2*i+2]='+',S[2*j+2*i-2][m-2*i+1]='/';}
	for(i=1;i<=a+1;i++) for(j=1;j<=c;j++) S[n-2*j+1][2*i-1]='|';
	for(i=1;i<=b;i++) for(j=1;j<=c;j++) S[2*j+2*i-2][m-2*i+2]='|';
	for(i=1;i<=a;i++) for(j=1;j<=c+1;j++) S[n-2*j+2][2*i]='-';
	for(i=1;i<=b;i++) for(j=1;j<=a;j++) S[2*i-1][m-2*j+1-2*i+2]='-';
	for(i=1;i<=n;Pc('\n'),i++) for(j=1;j<=m;j++) Pc(S[i][j]); 
}
int main(){
	//freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	int T;scanf("%d",&T);while(T--) Solve();
}

冲塔

首先考虑每个横坐标上只有两个点的部分分,那么肯定是对于每个列,都将两个点放在最大和最小值,那么一定不会超过。

我们继续考虑构成正方形的那个,可以发现就是两条对角线,这也可以看做将每一列不断往中间移动。

这启发我们先把每一列的最大值和最小值都填上,然后再从两边往中间,每一行只保留最小和最大的,因为中间肯定能被包含所以可以往中间移动,这也就构造性证明了一定有解。大样例不用fc就过了

因为一个塔被放弃了就不会继续操作这个塔了,所以用set维护,时间复杂度\(O(n\log n)\)

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=1e6+5,M=13,K=1e5+5,mod=998244353,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;
int n,m,k,X[N],Y[N],M1,M2,Fl[N],vis[N],Mx[N],Mi[N],O1[N],O2[N];set<int> Q[N];map<int,int> Id[N];
void I1(int p);void I2(int p);
void I1(int p){int p1=-1,p2=-1;
	while(!Q[p].empty()){
		int Ts=*Q[p].begin();Q[p].erase(Ts);
		if(!Mi[Ts]) {Mi[Ts]=p;O1[Ts]=1;Fl[Id[p][Ts]]=1;break;}if(!Mx[Ts]){Mx[Ts]=p;O2[Ts]=1;Fl[Id[p][Ts]]=1;if(Mx[Ts]<Mi[Ts]) swap(Mx[Ts],Mi[Ts]),swap(O1[Ts],O2[Ts]);break;}
		if(p<Mi[Ts]) {Fl[Id[p][Ts]]=1;Fl[Id[Mi[Ts]][Ts]]=0;p1=Mi[Ts];p2=O1[Ts];Mi[Ts]=p;O1[Ts]=1;break;}
		if(p>Mx[Ts]) {Fl[Id[p][Ts]]=1;Fl[Id[Mx[Ts]][Ts]]=0;p1=Mx[Ts];p2=O2[Ts];Mx[Ts]=p;O2[Ts]=1;break;} 
	}
	if(~p1) ~p2?I1(p1):I2(p1);
} 
void I2(int p){int p1=-1,p2=-1;
	while(!Q[p].empty()){
		int Ts=*Q[p].rbegin();Q[p].erase(Ts);
		if(!Mi[Ts]) {Mi[Ts]=p;O1[Ts]=-1;Fl[Id[p][Ts]]=1;break;}if(!Mx[Ts]){Mx[Ts]=p;O2[Ts]=-1;Fl[Id[p][Ts]]=1;if(Mx[Ts]<Mi[Ts]) swap(Mx[Ts],Mi[Ts]),swap(O1[Ts],O2[Ts]);break;}
		if(p<Mi[Ts]) {Fl[Id[p][Ts]]=1;Fl[Id[Mi[Ts]][Ts]]=0;p1=Mi[Ts];p2=O1[Ts];Mi[Ts]=p;O1[Ts]=-1;break;}
		if(p>Mx[Ts]) {Fl[Id[p][Ts]]=1;Fl[Id[Mx[Ts]][Ts]]=0;p1=Mx[Ts];p2=O2[Ts];Mx[Ts]=p;O2[Ts]=-1;break;} 
	}
	if(~p1) ~p2?I1(p1):I2(p1);
}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	int i,j;scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d%d",&X[i],&Y[i]),Id[X[i]][Y[i]]=i,Q[X[i]].insert(Y[i]),M1=max(M1,X[i]),M2=max(M2,Y[i]);
	for(i=1;i<=M1;i++)I1(i),I2(i);for(i=1;i<=n;i++) printf("%d",Fl[i]);
}

波特分组

首先发现因为总的数量为\(2n\),因此如果有其中一个超过\(n\)个,另一个就不会超过\(n\)个。也就是说只会有一边会出现爆掉的情况。

钦定第一个bot是A组,那么这\(k\)个bot分在同一组的方案数就可以分成两种情况:

1.可以找到一条分界线使得前面和后面选择的不一样,但是后面选择的因为爆掉了所以和前面一样了。这需要枚举一条大于\(n\)个的分界线,预处理后容易做到\(O(\sum k)\)

2.找不到这样的分界线,这需要枚举最后一个被钦定的bot之前的有几个选了和bot同样的颜色,要求两边都不能超过,容易发现这个是一个给定区间\([l,r],x\),求\(\sum\limits_{i=l}^{r}{C_{x}^{i}}\)的形式,是一个经典莫队。

综上可以做到\(O(n\sqrt n)\)。还跑得挺快。

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=2e5+5,M=13,K=1e5+5,mod=998244353,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;
int l,r,n,m,k,x,y,z,B[N],Qh;ll Ans[N],frc[N],Inv[N],Po[N],ToT,Ps[N],Sum[N],g[N];
ll mpow(ll x,int y=mod-2){ll Ans=1;while(y) y&1&&(Ans=Ans*x%mod),y>>=1,x=x*x%mod;return Ans;}
ll C(int x,int y){if(x<y||x<0||y<0) return 0;return frc[x]*Inv[y]%mod*Inv[x-y]%mod;}
struct Ques{int l,r,w,id;}Q[N];bool cmp(Ques x,Ques y){return (x.l/k)^(y.l/k)?x.l<y.l:((x.l/k)&1?x.r<y.r:x.r>y.r);}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	int i,j;scanf("%d%d",&n,&m);k=max(n/sqrt(m),1.0);for(Ps[0]=Po[0]=Inv[0]=frc[0]=i=1;i<=2*n+1;i++) frc[i]=frc[i-1]*i%mod,Inv[i]=mpow(frc[i]),Po[i]=Po[i-1]*(mod+1)/2%mod,Ps[i]=Ps[i-1]*2%mod;
	for(i=2*n;~i;i--) Sum[i]=(Sum[i+1]+C(i,n)*Po[i+1])%mod;
	for(i=1;i<=m;i++){
		scanf("%d",&x);for(j=1;j<=x;j++) scanf("%d",&B[j]);if(x>n) continue;
		for(j=1;j<=x;j++) Ans[i]+=(Sum[B[j-1]-j+1]-Sum[B[j]-j]+mod)*Ps[x-j+1]%mod+C(B[j]-j,n)*Po[B[j]-j]%mod*Ps[x-j]%mod;
		//for(i=1;i<=B[x];i++){while(R<x&&B[R+1]<i) R++;ToT+=C(i-R-1,n)*Po[i-R-(B[R+1]==i)]%mod*Ps[x-R-(B[R+1]==i)]%mod;cerr<<ToT%mod<<'\n';}
		Ans[i]=Ans[i]%mod*Po[x-1]%mod;Q[++Qh]=(Ques){B[x]-x,n-x,Po[B[x]-x]*Po[x-1]%mod,i};max(x,B[x]-n)^x&&(Q[++Qh]=(Ques){B[x]-x,max(x,B[x]-n)-1-x,mod-Po[B[x]-x]*Po[x-1]%mod,i},0);
		//for(i=max(x,B[x]-n);i<=n;i++) ToT+=C(B[x]-x,i-x)*Po[B[x]-x]%mod;
		//printf("%lld\n",ToT%mod*Po[x-1]%mod);
	}sort(Q+1,Q+Qh+1,cmp);l=r=0;ToT=1;for(i=1;i<=Qh;i++){
		while(r<Q[i].r) ToT+=C(l,++r);while(r>Q[i].r)ToT-=C(l,r--);
		while(l<Q[i].l) ToT=(ToT*2-C(l++,r))%mod;while(l>Q[i].l) ToT=(ToT%mod+C(--l,r))*(mod+1)/2%mod;
		Ans[Q[i].id]+=ToT%mod*Q[i].w%mod;
	}for(i=1;i<=m;i++) printf("%lld\n",(Ans[i]%mod+mod)%mod);
}

别急

什么大毒瘤码量题真是日了狗了。

首先这个东西建出图来显然是一个内向基环树。因此对于一个询问\((x,y)\),设\(d_x<d_y\),环上深度为\(0\)。可以分成三类讨论:\([0,d_x],[d_x,d_y],[d_y,\infty]\)

Case 1:\([d_y,\infty]\)

首先可以确定两个点跳到环上的一个时刻分别在什么位置。然后对于每个\(i\),且两个点都在环上且环和当前对应,则需要步数之差被两个环的长度的\(\gcd\)整除。这个可以用map维护三元组,查询的时候看看有没有即可。

Case 2:\([d_x,d_y]\)

这时深度较小的点已经跳到了环上,则可以将询问离线,然后dfs深度较小的点的那棵树。能跳到相当于它们的差模环长同余。则也是用map记二元组就好了。

Case 3:\([0,d_x]\)

同样考虑在较浅的树上dfs,则需要它们之差相等。这个也可用\(n\)个动态开点线段树维护,维护的时候只要知道一个点有没有被一条线段覆盖即可。

综上时间复杂度\(O(n\log n)\),代码死难写。

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=1e5+5,M=N*30+5,K=1e5+5,mod=998244353,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;
int n,m,k,x,y,z,X[N],Y[N],Ans[N];
struct Based{
	int Bg[N],En[N],H,cnt,Si[N],x,y,fa[N][20],Fl[N],d[N],vis[N],lg[N],f[N],Tp[N];vector<int> S[N];
	int GF(int x){return f[x]^x?f[x]=GF(f[x]):x;}
	void dfs(int x,int La,int Ts){Bg[x]=++H;Tp[x]=Fl[Ts];d[x]=d[La]+1;for(int i:S[x]) dfs(i,x,Ts);En[x]=H;}
	void BD(){
		int i,j;for(i=2;i<=n;i++) lg[i]=lg[i/2]+1;for(i=1;i<=n;i++) S[fa[i][0]].PB(i),f[i]=i;for(i=1;i<=n;i++) f[GF(fa[i][0])]=GF(i);
		for(i=1;i<=lg[n];i++) for(j=1;j<=n;j++) fa[j][i]=fa[fa[j][i-1]][i-1];
		for(i=1;i<=n;i++){if(GF(i)^i) continue;x=GF(i);while(!vis[x]) vis[x]=1,x=fa[x][0];Fl[x]=++cnt;}
		for(i=1;i<=n;i++) {if(!Fl[i]||d[i]) continue;d[y=i]=1;Si[Fl[y]]=1;x=fa[i][0];while(!Fl[x]) Si[Fl[x]=Fl[y]]++,d[x]=d[y]+1,x=fa[y=x][0];}
		for(i=1;i<=n;i++) if(Fl[i]) for(int j:S[i]) !Fl[j]&&(dfs(j,j,i),0);
	}
	int Jp(int x,int k){while(k) x=fa[x][lg[k&-k]],k-=k&-k;return x;}
}A,B;
namespace Tree{
	int L[M],R[M],f[M],cnt;void Cl(){for(int i=1;i<=cnt;i++)L[i]=R[i]=f[i]=0;cnt=0;}
	void Ins(int x,int y,int z,int &v,int l=1,int r=n){!v&&(v=++cnt);if(x<=l&&r<=y){f[v]+=z;return;}int m=l+r>>1;x<=m&&(Ins(x,y,z,L[v],l,m),0);y>m&&(Ins(x,y,z,R[v],m+1,r),0);}
	int Qry(int x,int v,int l=1,int r=n){if(f[v]) return 1;if(!v||l==r) return 0;int m=l+r>>1;return x<=m?Qry(x,L[v],l,m):Qry(x,R[v],m+1,r);}
}
namespace Solve1{
	int x,y,p;struct Ques{int x,y,id;}Cl,Is[N];vector<Ques> Ps[N];int Ro[N];map<pair<int,int>,int> g;
	void dfs1(int x){Is[x].x&&(Tree::Ins(Is[x].x,Is[x].y,1,Ro[Is[x].id]),0);for(Ques i:Ps[x]) Ans[i.id]|=Tree::Qry(B.Bg[i.x],Ro[i.y]);for(int i:A.S[x]) dfs1(i);Is[x].x&&(Tree::Ins(Is[x].x,Is[x].y,-1,Ro[Is[x].id]),0);}
	void dfs2(int x){Is[x].x&&(Tree::Ins(Is[x].x,Is[x].y,1,Ro[Is[x].id]),0);for(Ques i:Ps[x]) Ans[i.id]|=Tree::Qry(A.Bg[i.x],Ro[i.y]);for(int i:B.S[x]) dfs2(i);Is[x].x&&(Tree::Ins(Is[x].x,Is[x].y,-1,Ro[Is[x].id]),0);}
	void calc(){int i,j;
		for(i=1;i<=n;i++) A.d[i]<=B.d[i]&&!A.Fl[i]&&!B.Fl[i]&&(/*cerr<<B.Bg[i]<<' '<<B.En[i]<<'\n',*/Is[i]=(Ques){B.Bg[i],B.En[i],B.d[i]-A.d[i]},0);
		for(i=1;i<=m;i++) x=X[i],y=Y[i],!Ans[i]&&!A.Fl[x]&&!B.Fl[y]&&A.d[x]<=B.d[y]&&(Ps[x].PB((Ques){y,B.d[y]-A.d[x],i}),0);
		for(i=1;i<=n;i++) if(A.Fl[i]) for(int j:A.S[i]) !A.Fl[j]&&(dfs1(j),0);for(i=0;i<=n;i++) Ro[i]=0,Is[i]=Cl,Ps[i].clear();Tree::Cl();
		for(i=1;i<=n;i++) A.d[i]>B.d[i]&&!A.Fl[i]&&!B.Fl[i]&&(Is[i]=(Ques){A.Bg[i],A.En[i],A.d[i]-B.d[i]},0);
		for(i=1;i<=m;i++) x=X[i],y=Y[i],!Ans[i]&&!A.Fl[x]&&!B.Fl[y]&&A.d[x]>B.d[y]&&(Ps[y].PB((Ques){x,A.d[x]-B.d[y],i}),0);
		for(i=1;i<=n;i++) if(B.Fl[i]) for(int j:B.S[i]) !B.Fl[j]&&(dfs2(j),0);
	}
}
namespace Solve2{int x,y,p;
	struct Ques{int x,y;}Cl,Is[N];unordered_map<int,int> f[N];
	struct Edge{int x,y,id;};vector<Edge> Ps[N];
	void dfs1(int x){Is[x].x&&(f[Is[x].x][Is[x].y]++);for(Edge i:Ps[x]) Ans[i.id]|=f[i.x][i.y];for(int i:A.S[x]) dfs1(i);Is[x].x&&(f[Is[x].x][Is[x].y]--);}
	void dfs2(int x){Is[x].x&&(f[Is[x].x][Is[x].y]++);for(Edge i:Ps[x]) Ans[i.id]|=f[i.x][i.y];for(int i:B.S[x]) dfs2(i);Is[x].x&&(f[Is[x].x][Is[x].y]--);}
	void calc(){int i,j;
		for(i=1;i<=n;i++) !A.Fl[i]&&B.Fl[i]&&(p=B.Si[B.Fl[i]],Is[i]=(Ques){B.Fl[i],(A.d[i]+B.d[i])%p},0);
		for(i=1;i<=m;i++) !Ans[i]&&(A.Fl[X[i]]?0:A.d[X[i]])>(B.Fl[Y[i]]?0:B.d[Y[i]])&&(x=A.Jp(X[i],B.Fl[Y[i]]?0:B.d[Y[i]]),y=B.Jp(Y[i],B.Fl[Y[i]]?0:B.d[Y[i]]),/*cerr<<x<<' '<<y<<'\n',*/p=B.Si[B.Fl[y]],Ps[x].PB((Edge){B.Fl[y],((A.d[x]+B.d[y])%p),i}),0);
		for(i=1;i<=n;i++) if(A.Fl[i])for(int j:A.S[i]) !A.Fl[j]&&(dfs1(j),0);
		for(i=1;i<=n;i++) Is[i]=Cl,Ps[i].clear(),f[i].clear();
		for(i=1;i<=n;i++) !B.Fl[i]&&A.Fl[i]&&(p=A.Si[A.Fl[i]],Is[i]=(Ques){A.Fl[i],(B.d[i]+A.d[i])%p},0);
		for(i=1;i<=m;i++) !Ans[i]&&(B.Fl[Y[i]]?0:B.d[Y[i]])>(A.Fl[X[i]]?0:A.d[X[i]])&&(y=B.Jp(Y[i],A.Fl[X[i]]?0:A.d[X[i]]),x=A.Jp(X[i],A.Fl[X[i]]?0:A.d[X[i]]),/*cerr<<x<<' '<<y<<'\n',*/p=A.Si[A.Fl[x]],Ps[y].PB((Edge){A.Fl[x],((B.d[y]+A.d[x])%p),i}),0);
		for(i=1;i<=n;i++) if(B.Fl[i])for(int j:B.S[i]) !B.Fl[j]&&(dfs2(j),0);
	}
}
namespace Solve3{
	int p,x,y;struct Ques{int x,y,z;bool operator <(const Ques &B)const{return x^B.x?x<B.x:(y^B.y?y<B.y:z<B.z);};};map<Ques,int> f;
	void calc(){
		int i,j;for(i=1;i<=n;i++) A.Fl[i]&&B.Fl[i]&&(p=__gcd(A.Si[A.Fl[i]],B.Si[B.Fl[i]]),f[(Ques){A.Fl[i],B.Fl[i],((A.d[i]-B.d[i])%p+p)%p}]=1);
		for(i=1;i<=m;i++) x=A.Jp(X[i],max(A.d[X[i]],B.d[Y[i]])),y=B.Jp(Y[i],max(A.d[X[i]],B.d[Y[i]]))/*,cerr<<x<<' '<<y<<'\n'*/,p=__gcd(A.Si[A.Fl[x]],B.Si[B.Fl[y]]),Ans[i]|=f.count((Ques){A.Fl[x],B.Fl[y],((A.d[x]-B.d[y])%p+p)%p});
	}
}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout); 
	int i,j;scanf("%d%d",&n,&m);for(i=1;i<=n;i++) scanf("%d",&A.fa[i][0]);for(i=1;i<=n;i++) scanf("%d",&B.fa[i][0]);A.BD();B.BD();
	for(i=1;i<=m;i++) scanf("%d%d",&X[i],&Y[i]);Solve3::calc();Solve2::calc();Solve1::calc();for(i=1;i<=m;i++) puts(Ans[i]?"YES":"NO");
}
posted @ 2022-09-12 12:45  275307894a  阅读(216)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end