0225模拟赛

\(~~~~\) 雷宝出来谢罪!

\(~~~~\) 绑点是懦弱的表现。

黄金山脊/「CF1770E」Koxia and Tree

题意

\(~~~~\) \(n\) 个点的树的 \(k\) 个点上初始有权值 \(1\),其他点初始权值 \(0\)\(n-1\) 次操作,每次令一条没有选择过的边有 \(\frac{1}{2}\) 概率交换两个端点的权值。求最后从关键点中选择 \(m\) 个点,从某个点出发到达所有选择的点并回去的最短经过边数的期望。对 \(998244353\) 取模。
\(~~~~\) \(1\leq n\leq 5\times 10^5\).

题解

\(~~~~\) 很有意思,我不会签到题了。

\(~~~~\) 首先考虑维护任何时刻每个点存在关键点的概率,这可以通过讨论两边的点初始的概率求得,也就是求出:两个点的情况不变,\(u\)\(v\) 移动,\(v\)\(u\) 移动的概率。而我们注意到某条边操作过后那么这条边两边的关键点数再也不会变化了,而在这之前显然也不会变化,综上我们发现某条边两侧的点数只可能在 \(\Delta\leq 1\) 内,而具体情况取决于上面取出的概率。

\(~~~~\) 考虑最后算答案,会发现其实就是包含选出的 \(m\) 个点的极小树的边数 \(\times 2\),那么我们考虑两侧分别有 \(siz\)\(k-siz\) 个关键点的话,这条边就会贡 \(2\times siz\times (k-siz)\) 的长度,当然最后求期望就是维护三种 \(siz\) 情况的概率以及选 \(\binom{k}{m}\) 点的概率了。

代码
查看代码
#include <bits/stdc++.h>
#define PII pair<int,int>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
    T f=1;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
vector <int> G[500005];
int siz[500005],Fac[500005],Inv[500005],val[500005],P[500005],dep[500005];
void dfs(int u,int fa)
{
	siz[u]=val[u]; dep[u]=dep[fa]+1;
	for(int i=0;i<(int)G[u].size();i++)
	{
		int v=G[u][i];
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v];
	}
}
const int MOD=998244353,Inv2=(MOD+1)>>1;
inline int Add(int a,int b){a+=b;return a>=MOD?a-MOD:a;}
inline int Dec(int a,int b){a-=b;return a<0?a+MOD:a;}
inline int Mul(int a,int b){return 1ll*a*b%MOD;}
inline int qpow(int a,int b)
{
	int ret=1;
	while(b)
	{
		if(b&1) ret=Mul(ret,a);
		b>>=1;a=Mul(a,a);
	}
	return ret;
}
inline int C(int N,int R){return N<R?0:Mul(Fac[N],Mul(Inv[R],Inv[N-R]));}
struct Edge{
	int u,v;
	Edge(){}
	Edge(int U,int V){u=U,v=V;}
}E[500005];
int main() {
//	freopen("ridge.in","r",stdin);
//	freopen("ridge.out","w",stdout);
	int n,m,k;read(n);read(k);read(m);
	Fac[0]=1;
	for(int i=1;i<=500000;i++) Fac[i]=Mul(Fac[i-1],i);
	Inv[500000]=qpow(Fac[500000],MOD-2);
	for(int i=500000-1;i>=0;i--) Inv[i]=Mul(Inv[i+1],i+1);
	for(int i=1,x;i<=k;i++) read(x),val[x]=1;
	for(int i=1,u,v;i<n;i++)
	{
		read(u);read(v);
		G[u].push_back(v);
		G[v].push_back(u);
		E[i]=Edge(u,v);
	}
	dfs(1,0);
	for(int i=1;i<n;i++) read(P[i]);
	int All=C(k,m),Ans=0;
	for(int i=1;i<n;i++)
	{
		int u=E[P[i]].u,v=E[P[i]].v;
		if(dep[u]>dep[v]) swap(u,v);
		int NotChange=Add(Add(Mul(val[u],val[v]),Add(Mul(Mul(Dec(1,val[u]),val[v]),Inv2),Mul(Mul(Dec(1,val[v]),val[u]),Inv2))),Mul(Dec(1,val[u]),Dec(1,val[v])));
		int uTov=Mul(Mul(val[u],Dec(1,val[v])),Inv2);
		int vTou=Mul(Mul(val[v],Dec(1,val[u])),Inv2);
		
		Ans=Add(Ans,Mul(Dec(All,Add(C(siz[v],m),C(k-siz[v],m))),NotChange));
		Ans=Add(Ans,Mul(Dec(All,Add(C(siz[v]+1,m),C(k-siz[v]-1,m))),uTov));
		Ans=Add(Ans,Mul(Dec(All,Add(C(siz[v]-1,m),C(k-siz[v]+1,m))),vTou));
		
		int Vu=val[u],Vv=val[v];
		val[u]=Add(Mul(Dec(1,Mul(Dec(1,Vv),Inv2)),Vu),Mul(Mul(Dec(1,Vu),Inv2),Vv));
		val[v]=Add(Mul(Dec(1,Mul(Dec(1,Vu),Inv2)),Vv),Mul(Mul(Dec(1,Vv),Inv2),Vu));
	}
	printf("%d",Mul(Mul(Ans,2),qpow(All,MOD-2)));
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。

3 2 2
1 3
1 2
2 3
1 2

5 3 3
1 3 5
1 2
1 3
2 4
2 5
2 3 1 4
*/

PICO-8/「ABC276Ex」Construct a Matrix

题意

\(n\times n\) 的矩阵仅含 \(0,1,2\)\(q\) 个限制:左上角 \((x_1,y_1)\),右下角 \((x_2,y_2)\) 的子矩阵的乘积 \(\bmod 3=k\),求构造出合法矩阵或说明无解。
\(1\leq n\leq 1500,1\leq q\leq 1500\).

题解

\(~~~~\) 先发现如果一个矩阵内有 \(0\),那么这个子矩阵的结果肯定是 \(0\),反之我们发现 \(1,2\) 有类似于 \(0,1\) 做异或的效果,那么我们就可以列出有 \(n^2\) 个元素的异或方程组,拿个 \(\mathcal{O(\frac{(n^2)^3}{\omega})}\) 解一解就好了。当然这肯定过不了。

\(~~~~\) 我们考虑:一个子矩阵结果为 \(1\) 那就是有偶数个 \(2\),结果为 \(2\) 那就是有奇数个 \(2\),那限制奇偶性考虑加法跟直接在异或意义下没啥区别,所以我们用前缀和来限制即可,这样一个方程只会涉及 \(4\) 个元素,并且必然有重复元素不然数据就会水qwq,那么这个做法就未来可期。

\(~~~~\) 那么就把 \(q\) 个询问分成 \(0\) 和非 \(0\) 的部分,非 \(0\) 部分用上面的异或方程解出来,\(0\) 部分就直接矩阵内没有占位的全部填 \(0\) 即可。同时如果判断出方程无解或者 \(0\) 部分的矩阵被填满了那整个问题就无解即可。

代码
查看代码
#include <bits/stdc++.h>
#define PII pair<int,int>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
    T f=1;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
int n,q,cnt;
int Map[4005][4005],S[4005][4005],S2[4005][4005];
bitset<8005>B[2005];
struct op{
	int l1,r1,l2,r2,val;
	op(){}
	op(int L1,int R1,int L2,int R2,int Val){l1=L1,r1=R1,l2=L2,r2=R2,val=Val;}
};
vector <op> V1,V2;
vector <PII> V;
inline int ID(PII x){return lower_bound(V.begin(),V.end(),x)-V.begin()+1;}
int main() {
	read(n);read(q);
	for(int i=1;i<=q;i++)
	{
		int a,b,c,d,e;
		read(a);read(c);read(b);read(d);read(e);
		if(!e) V1.push_back(op(a,b,c,d,e));
		else
		{
			if(a-1&&b-1) V.push_back(mp(a-1,b-1));
			if(c&&b-1) V.push_back(mp(c,b-1));
			if(a-1&&d) V.push_back(mp(a-1,d));
			V.push_back(mp(c,d)); V2.push_back(op(a,b,c,d,e));
			S[a][b]++; S[c+1][b]--; S[a][d+1]--; S[c+1][d+1]++; 
		}
	}
	sort(V.begin(),V.end());
	V.erase(unique(V.begin(),V.end()),V.end());
//	for(int i=0;i<V.size();i++) cerr<<V[i].first<<" "<<V[i].second<<endl;
	for(int i=0;i<(int)V2.size();i++)
	{
		op x=V2[i];
		int l1=x.l1,r1=x.r1,l2=x.l2,r2=x.r2,val=x.val;cnt++;
		if(l1-1&&r1-1) B[cnt][ID(mp(l1-1,r1-1))]=1;
		if(l2&&r1-1) B[cnt][ID(mp(l2,r1-1))]=1;
		if(l1-1&&r2) B[cnt][ID(mp(l1-1,r2))]=1;
		B[cnt][ID(mp(l2,r2))]=1; B[cnt][V.size()+1]=(val==2); 
	}
	int L=1;
	for(int i=1;i<=(int)V.size();i++)
	{
		int pos=-1;
		for(int k=L;k<=cnt;k++)
			if(B[k][i]) {pos=k;break;}
		if(pos==-1) continue;
		swap(B[L],B[pos]);
		for(int k=1;k<=cnt;k++)
			if(k!=L&&B[k][i]) B[k]^=B[L];
		L++;
	}
	for(int i=L;i<=cnt;i++)
		if(B[i][V.size()+1]) return puts("No")&0;
	for(int i=1;i<L;i++)
	{
		int l=B[i]._Find_first();
		Map[V[l-1].first][V[l-1].second]=B[i][V.size()+1];
	}
	for(int i=n;i>=1;i--)
		for(int j=n;j>=1;j--) Map[i][j]^=Map[i-1][j-1]^Map[i-1][j]^Map[i][j-1];
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			S[i][j]=S[i][j]+S[i-1][j]+S[i][j-1]-S[i-1][j-1];
			if(!S[i][j]) S2[i][j]=1,Map[i][j]=-1;
			S2[i][j]=S2[i][j]+S2[i-1][j]+S2[i][j-1]-S2[i-1][j-1]; 
		}
	}
	for(int i=0;i<(int)V1.size();i++)
	{
		int a=V1[i].l1,b=V1[i].r1,c=V1[i].l2,d=V1[i].r2;
		if(S2[c][d]-S2[c][b-1]-S2[a-1][d]+S2[a-1][b-1]==0) return puts("No")&0;
	}
	puts("Yes");
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++) printf("%d ",Map[i][j]+1);
		puts("");
	}
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。

不想动T2这堆shi
但是好像也没办法啊,一个半小时,忍忍就逝了 
2 3
1 1 1 2 0
1 2 2 2 1
2 2 1 2 2
*/

沉思/「ARC146E」Simple Speed

题意

\(~~~~\) \(n\) 个高度,第 \(i\) 个高度有 \(c_i\) 个。求有多少种序列其相邻元素的差为 \(1\)
\(~~~~\) \(1\leq n\leq 5\times 10^5,1\leq c_i\leq 5\times 10^5\).

题解

\(~~~~\) 记录 \(dp_{i,j,k,x,y}\) 表示当前考虑前 \(i\) 个高度,下一个高度需要左边补 \(j\) 个,右边补 \(k\) 个,同时左/右端点是/否已经放了。

\(~~~~\) 那么注意到 \(|j-k|\leq 1\) ,因为最多只能有一个放在端点,其他的必须对称才能接上,所以这两维和一维差别不大,并且这个值应该和 \(c_i-c_{i-1}\) 非常接近,所以就是这两维总的算一个常数。

\(~~~~\) 那么现在dp状态就非常少了,所以直接dp就好了。

代码
查看代码
#include <bits/stdc++.h>
#define ll long long
#define PII pair<int,int>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
    T f=1;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
int n,C[500005];
inline int Abs(int x){return x>=0?x:-x;}
namespace Subtask12{
	int Ans,Sum=0;
	void dfs(int t,int lst=-1)
	{
		if(t==Sum+1)
		{
			Ans++;
			return;
		}
		for(int i=1;i<=n;i++)
		{
			if((lst==-1||Abs(lst-i)==1)&&C[i]) C[i]--,dfs(t+1,i),C[i]++;
		}
	}
	void Main()
	{
		for(int i=1;i<=n;i++) Sum+=C[i];
		dfs(1);
		printf("%d",Ans);
		exit(0);
	}
}
int Fac[500005],Inv[500005];
const int MOD=998244353;
inline int Add(int a,int b){return (a+b)%MOD;}
inline int Dec(int a,int b){return (a-b+MOD)%MOD;}
inline int Mul(int a,int b){return 1ll*a*b%MOD;}
inline int qpow(int a,int b)
{
	int ret=1;
	while(b)
	{
		if(b&1) ret=Mul(ret,a);
		b>>=1;a=Mul(a,a);
	}
	return ret;
}
inline int Binom(int N,int r){return N<r?0:Mul(Fac[N],Mul(Inv[r],Inv[N-r]));}
namespace SubtaskO{
	struct node{
		int j,k,x,y;
		node(){}
		node(int J,int K,int X,int Y){j=J,k=K,x=X,y=Y;}
	};
	ll Zip(node x){return ((1ll*x.j*500001+x.k)*2+x.x)*2+x.y;}
	node UnZip(ll x)
	{
		node res;
		res.y=x&1; x>>=1;
		res.x=x&1; x>>=1;
		res.k=x%500001; x/=500001;
		res.j=x;
		return res;
	}
	map<ll,ll>dp[2];
	void Clear(map<ll,ll> &x){map<ll,ll>Tmp;swap(Tmp,x);}
	void Main()
	{
		Fac[0]=1;
		for(int i=1;i<=500000;i++) Fac[i]=Mul(Fac[i-1],i);
		Inv[500000]=qpow(Fac[500000],MOD-2);
		for(int i=500000-1;i>=0;i--) Inv[i]=Mul(Inv[i+1],i+1); 
		dp[0][0]=1;
		for(int i=1;i<=n;i++)
		{
			for(auto &it:dp[!(i&1)])
			{
				node Pre=UnZip(it.first);int Val=it.second;
				if(!Val) continue;
				int j=Pre.j,k=Pre.k,x=Pre.x,y=Pre.y;
				for(int xx=0;xx<=(!x);xx++)
				{
					for(int yy=0;yy<=(!y);yy++)
					{
						int u=C[i]-j-xx,v=C[i]-k-yy;
						if(u<0||v<0||Abs(u-v)>1) continue; 
						/*接下来需要有9种转移*/
						/*我先别急*/
						int R[5],L[5];
						R[0]=k; R[1]=yy; R[2]=v;
						L[0]=j; L[1]=xx; L[2]=u;
						for(int ind1=0;ind1<=2;ind1++)
						{
							if(!R[ind1]) continue;
							for(int ind2=0;ind2<=2;ind2++)
							{
								if(!L[ind2]) continue;
								R[ind1]--; L[ind2]--;
								bool fail=false;
								if(R[2]!=L[2]) fail=true;
								if(R[0]!=L[0]) fail=true;
								if(xx&&ind2!=1) fail=true;
								if(yy&&ind1!=1) fail=true;
								if(x&&ind2!=0) fail=true;
								if(y&&ind1!=0) fail=true;
								if(!xx&&!x&&ind2!=2) fail=true;
								if(!yy&&!y&&ind1!=2) fail=true;
								if(!fail)
								{
									ll id=Zip(node(v,u,x|xx,y|yy));
									dp[i&1][id]=Add(dp[i&1][id],Mul(Val,Binom(C[i]-1,R[2])));
								}
								R[ind1]++; L[ind2]++;
							}
						}
					}
				}
			}
			Clear(dp[!(i&1)]);
		}
		printf("%lld",dp[n&1][Zip(node(0,0,1,1))]);
		exit(0);
	}
}
int main() {
//	freopen("reflection.in","r",stdin);
//	freopen("reflection.out","w",stdout);
	int Maxn=0;read(n);
	for(int i=1;i<=n;i++) read(C[i]),Maxn=max(Maxn,C[i]);
//	if((n<=3&&Maxn<=5)||(n<=2)) Subtask12::Main();
	SubtaskO::Main();
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。

考虑dp:记 dp_{i,j,k,x,y} 表示当前为第i种高度,有j个下个高度往左边接,k个下个高度往右边接,且是否要作为整个的左/右端点的出现
用map存状态应该不会很多?
因为j和k应该要非常接近,否则这些不能合并上
差距最多为1,否则根本合不上
同时合适的取值范围也不大 
然后就是一堆大粪讨转移? 
*/

镜之寺庙/「ARC150F」Constant Sum Subsequence

没看,没补,没时间

posted @ 2023-02-26 22:58  Azazеl  阅读(44)  评论(0)    收藏  举报