省选模拟28

说句闲话
学了会儿头插dp,转移是这样写的,\(Chen\_jr\)锐评:插头你还短路,你不烧谁烧
于是脑子烧坏了来补题解

(!is_d) && (!is_r) && mp[i+1][j] & mp[i][j+1]// need to make a new component
		&& ( H.Push( u+ts[j-1]+2*ts[j],val ),0 );

(!is_d) && (is_r)
	&& (  ( mp[i+1][j] && (H.Push(u,val),0) )//down
		|| ( mp[i][j+1] && (H.Push(u-is_r*ts[j-1]+is_r*ts[j],val ),0) ) );//right

(is_d) && (!is_r)
	&& (  ( mp[i][j+1] && (H.Push(u,val),0) )//right 
		|| ( mp[i+1][j] && (H.Push(u-is_d*ts[j]+is_d*ts[j-1],val ),0) ) );//down
					
(is_d==1 && is_r==2)
	&& ( H.Push( u-2*ts[j-1]-ts[j],val ),0 );

(is_r==1 && is_d==2 ) && ( i == Edx && j == Edy)
	&& (ans+=val);

A.装备

水题,成对给出先考虑建边,发现是一对内向树森林,有环的一定废,否则翻转一个位置即将它到跟的边方向全翻转,可以无脑上LCT,只需要MakerootAccess,从高位到低位贪心翻即可,要注意不能在低位影响高位的结果,除非高位翻与不翻的权值一样

点击查看代码
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=2e5+10;

vector<int>Ans;
map<pii,int>Map;
int n,m,Lim;
int w[maxn];
int a[maxn],b[maxn],rk[maxn];

struct LCT_tree{
	#define lch V[p].son[0]
	#define rch V[p].son[1]
	#define Son(p) (p==V[V[p].fa].son[1])
	#define Isroot(p) (V[V[p].fa].son[0]!=p && V[V[p].fa].son[1]!=p)
	struct Vertex{int son[2],siz,val,maxi,fa,lazy;}V[maxn];
	int tot;
	int New(int fa){ ++tot;V[tot].siz=1;V[tot].fa=fa;return tot; }

	void Pushup(int p){ V[p].siz=V[lch].siz+V[rch].siz+1;V[p].maxi=max({ V[lch].maxi,V[rch].maxi,V[p].val }); }
	void Pushdown(int p){
		if(!V[p].lazy)return;
		swap(V[lch].son[0],V[lch].son[1]); swap(V[rch].son[0],V[rch].son[1]);
		V[lch].lazy^=1,V[rch].lazy^=1,V[p].lazy^=1;
	}
	void Spread(int p){ if(!Isroot(p))Spread(V[p].fa); Pushdown(p); }

	void Rotate(int p){
		int f=V[p].fa,lf=V[f].fa,s=Son(p),ls=Son(f);
		if(!Isroot(f))V[lf].son[ls]=p;
		V[p].fa=lf;
		V[f].son[s]=V[p].son[s^1]; V[V[p].son[s^1]].fa=f;
		V[p].son[s^1]=f,V[f].fa=p;
		Pushup(f),Pushup(p);
	}
	void Splay(int p){
		Spread(p);
		for(int f=V[p].fa;!Isroot(p);Rotate(p),f=V[p].fa)
			if(!Isroot(f))Rotate(Son(f)==Son(p) ? f : p);
	}

	int Access(int x){ int p; for(p=0;x;p=x,x=V[x].fa) Splay(x),V[x].son[1]=p,Pushup(x); return p; }
	void Makeroot(int p){ p=Access(p);swap(V[p].son[0],V[p].son[1]); V[p].lazy^=1; }
	int Findroot(int p){ Access(p);Splay(p);Pushdown(p);while(lch)p=lch,Pushdown(p); Splay(p);return p; }
	vector<int>vec;
	void Flat(int p){ if(!p)return;Flat(lch);vec.emplace_back(p);Flat(rch); }
	void Refresh(int p){ if(!p)return;Refresh(lch),Refresh(rch);Pushup(p); }
	void Work(int x,int Tim){
		Access(x);Splay(x);
		if(V[x].siz-1>Lim || V[x].maxi>Tim)return;
		//assert(V[x].siz>1 && V[x].maxi>0);
		Lim-=(V[x].siz-1);
		vec.resize(0);Flat(x);
		for(int i=0;i+1<vec.size();++i){
			int u=rk[vec[i]],v=rk[vec[i+1]],id=Map[pii(v,u)];
			Ans.emplace_back(id);//assert(id);
			swap(a[id],b[id]);
			Map.erase(pii(v,u));Map[pii(u,v)]=id;
			V[vec[i]].val=(w[u]==w[v] ? 0 : id);
		}
		V[x].val=0;
		Refresh(x);Makeroot(x);
	}
}T;

int tot,siz[maxn];

struct Graph{
	struct eg{ int from,to,next; }e[maxn];
	int len,head[maxn];int deg[maxn];
	void lqx(int from,int to)
	{ e[++len].from=from,e[len].to=to,e[len].next=head[from],head[from]=len;++deg[to]; }
	int dfn[maxn],low[maxn],st[maxn],top,bel[maxn],Te;bool vis[maxn];
	void Tarjan(int u){
		dfn[u]=low[u]=++Te;st[++top]=u;vis[u]=true;
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;
			if(!dfn[v])Tarjan(v),low[u]=min(low[u],low[v]);
			else if(vis[v])low[u]=min(low[u],dfn[v]);
		}
		if(dfn[u]==low[u]){
			++tot;
			while(st[top+1]!=u){
				++siz[tot];
				bel[st[top]]=tot;
				vis[st[top--]]=false;
			}
		}
	}
	void Build(){
		queue<int>q;
		Rep(i,1,tot)if(!deg[i] && siz[i]==1)q.push(i);
		while(!q.empty()){
			int u=q.front();q.pop();
			vis[u]=true;
			for(int i=head[u];i;i=e[i].next){
				int v=e[i].to;
				T.V[v].fa=u;q.push(v);
				T.V[v].val=(w[rk[v]]==w[rk[u]] ? 0 : Map[pii(rk[v],rk[u])]);
			}
		}
		Rep(i,1,tot)if(!deg[i] && siz[i]==1)T.Makeroot(i);
	}
}G,F;

void Work(int x,int Tim){ 
	if(!F.vis[G.bel[x]])return;
	T.Work(G.bel[x],Tim); 
}

void solve(){
	cin>>n>>m>>Lim;Rep(i,1,n)cin>>w[i],T.New(0);
	Rep(i,1,m){ cin>>a[i]>>b[i];Map[pii(a[i],b[i])]=i;G.lqx(a[i],b[i]); }
	Rep(i,1,n)if(!G.dfn[i])G.Tarjan(i);
	Rep(i,1,n)if(siz[G.bel[i]]==1)rk[G.bel[i]]=i;
	Rep(i,1,G.len){
		int u=G.bel[G.e[i].from],v=G.bel[G.e[i].to];
		if(u==v)continue;
		F.lqx(v,u);
	}F.Build();
	Dwn(i,m,1)if(w[a[i]]<w[b[i]])Work(a[i],i);
	cout<<Ans.size()<<"\n";
	for(auto it : Ans)cout<<it<<"\n";
}

int main (){
	fre(equipment);
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; 
}

B.比赛

看完数据范围套路设\(f_{l,r,k}\),表示区间\([l,r]\)最后\(k\)胜出的概率,这样从\(k\)将区间一分为二,左右互不影响,变成子问题,发现子问题的\(k\)一定为左右边界其一,于是简化状态\(f_{l,r,0/1/2}\),表示左边界出线,右边界出线,左右都出线,转移即可。发现不太会算概率,于是直接考虑计数方案数。可以理解为,钦定若干比赛结果,计数满足这些比赛结果的比赛顺序的方案数,乘上达到钦定结果的概率,再除以比赛顺序的总数,即为其概率。

tmd又被n=1坑了

点击查看代码
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=5e2+10,Mod=998244353,inv2=(Mod+1)>>1;

int pw(int x,int p){int res=1,base=x;while(p){if(p&1)res=1LL*res*base%Mod;base=1LL*base*base%Mod;p>>=1;}return res;}
int Inv(int x){return pw(x,Mod-2);}
int fac[maxn],ifac[maxn],inv[maxn];

int n,a[maxn];
int dp[maxn][maxn][3],vis[maxn][maxn][3];
int C[maxn][maxn],P[maxn][maxn];

int Sol(int l,int r,int k){
	if(vis[l][r][k])return dp[l][r][k];
	vis[l][r][k]=true;

	if(l==r)return dp[l][r][k]=1;
	if(l+1==r && k==2)return dp[l][r][k]=1;

	if(k==0){
		int res=0;
		Rep(i,l+1,r){
			int val1=Sol(l,i,2),val2=Sol(i,r,0);
			res=(res+1LL*val1*val2%Mod*P[l][i]%Mod*C[r-l-1][r-i])%Mod;
		}
		return dp[l][r][k]=res;
	}
	if(k==1){
		int res=0;
		Dwn(i,r-1,l){
			int val1=Sol(l,i,1),val2=Sol(i,r,2);
			res=(res+1LL*val1*val2%Mod*P[r][i]%Mod*C[r-l-1][i-l])%Mod;
		}
		return dp[l][r][k]=res;
	}
	if(k==2){
		int res=0;
		Rep(i,l+1,r-1){
			int val1=Sol(l,i,2),val2=Sol(i,r,2),tmp=1LL*val1*val2%Mod*C[r-l-2][i-l-1]%Mod;
			res=(res+1LL*tmp*P[l][i])%Mod;
			res=(res+1LL*tmp*P[r][i])%Mod;
		}
		return dp[l][r][k]=res;
	}
	//assert(k>=0 && k<=2);
	//return dp[l][r][k]=0;
	return 0;
}


void solve(){
	cin>>n;Rep(i,1,n)cin>>a[i];

	fac[0]=ifac[0]=1;Rep(i,1,n)fac[i]=1LL*fac[i-1]*i%Mod;
	ifac[n]=Inv(fac[n]);Dwn(i,n-1,1)ifac[i]=1LL*ifac[i+1]*(i+1)%Mod;
	C[0][0]=1;Rep(i,1,n){ C[i][0]=1;Rep(j,1,i)C[i][j]=(C[i-1][j]+C[i-1][j-1])%Mod; }
	Rep(i,1,n)Rep(j,1,n)P[i][j]=1LL*a[i]*Inv(a[i]+a[j])%Mod;

//	cerr<<Sol(1,2,1)<<"\n";
	cout<<1LL*Sol(1,n,0)*ifac[n-1]%Mod<<"\n";
	Rep(i,2,n-1)
		cout<<1LL*Sol(1,i,1)*Sol(i,n,0)%Mod*ifac[n-1]%Mod*C[n-1][i-1]%Mod<<"\n";
	if(n!=1)cout<<1LL*Sol(1,n,1)*ifac[n-1]%Mod<<"\n";
}

int main (){ fre(tournament);ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }

C.取石子游戏

不会证SG,打表也看不出来,题解说啥我干啥

点击查看代码
// ubsan: undefined
// accoders
#pragma GCC target("avx")
#pragma GCC optimize(3)
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=280000+10,Mod=998244353,Inv2=(Mod+1)>>1;

int n,m;
int Add(int x,int y){ return (x+y)>m ? x+y-m-1 : x+y; }
int Ckadd(int x,int y){ return (x+y)>=Mod ? x+y-Mod : x+y; }
int Cksub(int x,int y){ return x-y<0 ? x-y+Mod : x-y; }

struct Ver{
	int f[21];
	int &operator[](const int &i){ return f[i]; }
	int operator[](const int &i)const{ return f[i]; }
	void Clear(){ memset(f,0,sizeof(f)); }
	friend Ver operator + (const Ver &A,const Ver &B){
		static Ver res;
		Rep(i,0,m)res[i]=Ckadd(A[i],B[i]);
		return res;
	}
	friend Ver operator - (const Ver &A,const Ver &B){
		static Ver res;
		Rep(i,0,m)res[i]=Cksub(A[i],B[i]);
		return res;
	}
	friend Ver operator * (const Ver &A,const Ver &B){
		static Ver res;res.Clear();
		Rep(i,0,m)Rep(j,0,m)res[Add(i,j)]=(res[Add(i,j)]+1LL*A[i]*B[j])%Mod;
		return res;
	}
	friend Ver operator * (const Ver &A,const int &x){
		static Ver res;
		Rep(i,0,m)res[i]=1LL*A[i]*x%Mod;
		return res;
	}
	
}F[21][maxn],tmp[maxn];

int V=1<<17;
void FWT_XOR(Ver f[],int opt){
	if(opt==-1)opt=Inv2;
	for(int m=1;m<V;m<<=1)for(int i=0;i<V;i+=(m<<1))for(int j=0;j<m;++j)
	{Ver x=f[i+j],y=f[i+j+m];f[i+j]=(x+y)*opt,f[i+j+m]=(x-y)*opt;}
}
int G[maxn],H[maxn];
void FWT(int f[],int opt){
	if(opt==-1)opt=Inv2;
	for(int m=1;m<V;m<<=1)for(int i=0;i<V;i+=(m<<1))for(int j=0;j<m;++j)
	{int x=f[i+j],y=f[i+j+m];f[i+j]=1LL*(x+y)*opt%Mod,f[i+j+m]=1LL*(x-y)*opt%Mod;}
}

int cnt[maxn];

void solve(){
	cin>>n>>m;
	V=1<<(__lg((100000/(m+1)))+1);
	Rep(i,1,n)++F[i][0][0],FWT_XOR(F[i],1);
	Rep(t,1,n){
		int len,c,x;cin>>len>>c;++cnt[c];
		for(int i=0;i<V;++i)tmp[i].Clear();
		Rep(i,1,len){ cin>>x; ++tmp[x/(m+1)][x%(m+1)]; }
		FWT_XOR(tmp,1);	
		for(int i=0;i<V;++i)F[c][i]=F[c][i]*tmp[i];
	}
	Rep(i,1,n)FWT_XOR(F[i],-1);
	V=1<<18;
	G[0]=1;FWT(G,1);
	Rep(c,1,n)if(cnt[c]){
		cerr<<c<<"\n";
		for(int i=0;i<V;++i)H[i]=0;
		for(int i=0;i<=V/(m+1);++i)Rep(j,0,m)
			H[i*(m+1)+j]=(H[i*(m+1)+j]+F[c][i][j])%Mod;
		bool fg=true;
		for(int i=0;i<V;++i)fg&=(!H[i]);
		assert(!fg);
		FWT(H,1);
		for(int i=0;i<V;++i)G[i]=1LL*G[i]*H[i]%Mod;
	}
	FWT(G,-1);
	int ans=0;for(int i=1;i<V;++i)ans=(ans+G[i])%Mod;
	cout<<(ans+Mod)%Mod;
}

int main (){ fre(nim);ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }

posted @ 2023-02-09 21:42  Delov  阅读(20)  评论(0编辑  收藏  举报