250510 模拟赛

分数:\(50+10+15=75\),被吊起来打,大家随随便便就拿到我分数的 \(3\)\(+\)

八点开始。T1 是好玩的交互题,然而只能拿到五十分/求放过。题面下边写着 勇于尝试 然后我把下发的 sample.cpp 交了得到 \(25\) 分。乱写了一堆在八点五十左右拿到了 \(50\) 分然后就走了。

下一次交题居然就是快 \(11:40\) 了,写了 T3 的一个 \(15\) 分暴力交了,过了 \(7\) 分钟交了 T2 的暴力,然后我整场只有五条提交记录。太水了。感觉明显是有 sd 省集后遗症的。

说实话我写总结的时候已经忘了这场比赛了。


T1 竞赛图

原题

考场上写了一个点向所有点连边的性质(二分找)。

后来知道有一个结论,竞赛图中至少存在一点到其余任何点的距离不大于 \(2\)。证明:设图上出度最大的点为 \(x\),从 \(x\) 出发有连边的点集为 \(S\),对于一点 \(y\not \in S\),如果从 \(S\) 中任意一点出发都没有向 \(y\) 的连边,那么 \(y\) 有向 \(S\) 内所有点的连边,以及向 \(x\) 的连边,度数大于 \(x\),产生矛盾。

然后考虑设 \(solve(V)\) 返回 \(V\) 中一个到集合内所有点距离 \(\le 2\) 的点。

  • 任意选择 \(V\) 中一个点 \(x\)

  • 如果 \(x\)\(V\) 内所有点都有连边,返回 \(x\),否则选择向 \(x\) 连边的集合 \(V'\),返回 \(solve(V')\)

然后就是想一下感觉不太对,但是仔细想一想就会发现它是对的。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=310;
int nid[N],id[N],tmp,cnt;
int e[N][N];
bool sense(int i,int j);
inline bool que(int x,int y)
{
	if(~e[x][y])return e[x][y];
	e[x][y]=sense(x,y);e[y][x]=e[x][y]^1;
	return e[x][y];
}
int altar(int n)
{
	memset(e,-1,sizeof e);
	srand(time(0));
	int tmp=n;
	for(int i=1;i<=n;i++)id[i]=i;
	while(tmp>1)
	{
		int k=rand()%tmp+1;swap(id[1],id[k]);
		cnt=0;bool f=true;
		for(int i=2;i<=tmp;i++)
		{
			if(que(id[i],id[1]))
			{
				f=false;
				nid[++cnt]=id[i];
			}
		}
		if(f)return id[1];
		swap(id,nid);tmp=cnt;
	}
	return id[1];
}

T2 拓扑序

原题

很牛的 dp 题。考场上只写了排列。

想到把问题转化为计算每个点在每个位置出现的次数。然后设 \(f_{x,i}\) 表示考虑到 \(x\),前面有 \(i\) 个点的方案数。所以有:

\[f_{fa_{x},j+k}\leftarrow f_{x,j}\times \binom{j+k-1}{j}\times\binom{siz_{fa_{x}}-j-k-1}{siz_{x}-j-1}\times C \]

其中 \(C\)\(fa_{x}\)\(x\) 子树之外的拓扑序数量。然后发现这个 dp 要对每个点做一次,而每次 dp 的复杂度是 \(O(n^2)\) 的,一共是 \(O(n^3)\),不能过。

考虑优化,发现每次 dp 的过程是非常相似的。把每种状态看作有向图的一个节点,转移系数为边权,发现 答案的计算可以从 \(f_{i,\star}\) 开始。优化之后只需要做一次 dp,时间复杂度为 \(O(n^2)\)

这么神的 dp 题下一次要努力写写暴力。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{
	int t=0;char h=getchar();
	while(!isdigit(h))h=getchar();
	while(isdigit(h))t=(t<<1)+(t<<3)+(h^48),h=getchar();
	return t;
}
void write(int x)
{
	if(x>9)write(x/10);putchar(x%10+'0');
}
const int mod=1e9+7;
const int N=5010;
int lk[N],nxt[N],to[N],len=1;
inline void insert(int x,int y)
{
	to[++len]=y;nxt[len]=lk[x];lk[x]=len;
}
inline ll quikp(ll a,int b)
{
	ll res=1;
	while(b)(b&1)&&((res*=a)%=mod),(a*=a)%=mod,b>>=1;
	return res;
}
ll fac[N],inv[N];
inline ll c(int n,int m)
{
	if(n<m||m<0)return 0;
	return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
ll g[N];
int siz[N];
void dfs1(int x)
{
	siz[x]=g[x]=1;
	for(int i=lk[x],y;i;i=nxt[i])
	{
		dfs1(y=to[i]);
		siz[x]+=siz[y];
		(g[x]*=g[y]*inv[siz[y]]%mod)%=mod;
	}
	(g[x]*=fac[siz[x]-1])%=mod;
}
ll f[N][N];
ll ans[N];
void dfs2(int x)
{
	ans[x]=f[x][0]*g[x]%mod;
	for(int i=lk[x],y=to[i];i;i=nxt[i],y=to[i])
	{
		ll tmp=g[x]*quikp(c(siz[x]-1,siz[y])*g[y]%mod,mod-2)%mod;
		for(int j=0;j<siz[y];j++)
			for(int k=1;k<=siz[x]-siz[y];k++)
				(f[y][j]+=c(j+k-1,j)*c(siz[x]-j-k-1,siz[y]-j-1)%mod*f[x][j+k]%mod*tmp%mod)%=mod;
		dfs2(y);
	}
}
int n,x;
int main()
{
	// freopen("b.in","r",stdin);

	n=read();fac[0]=1;
	for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
	inv[n]=quikp(fac[n],mod-2);
	for(int i=n-1;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
	for(int i=2;i<=n;i++)x=read(),insert(x,i);
	for(int i=0;i<n;i++)f[1][i]=read();
	dfs1(1);dfs2(1);
	for(int i=1;i<=n;i++)write(ans[i]),putchar(' ');puts("");
	return 0;
}

T3 背包

原题

tag:笛卡尔树

我不会!先走了。

posted @ 2025-05-16 17:06  baiguifan  阅读(44)  评论(0)    收藏  举报