[DMY]2024 CSP-S 模拟赛 Day 6

题目 T1 T2 T3 T4
当前分数 \(\color{#00CC00}100\) \(\color{#E68A00}10\) \(\color{#00CC00}100\) \(\color{#E68A00}20\)

离 A 掉一道题最近的一次。

过程

看完 T1 以后,想先构一个 \(\mathcal{O}(n^3)\) 的暴力,但是发现只有 10pts,而且算法复杂度接近 \(\mathcal{O}(n^4)\),所以果断放弃。

把链的限制写了(然后亏大了),然后开始在 CS 上面画画。画了一会发现一个简单的 dp 思路,但是是 \(\mathcal{O}(n^2)\) 的。不过分也不少,就写了。调完以后时间已经过了 \(1\frac{1}{12}h\)

发现我的这个 dp 枚举只在于一个点,所以考虑怎么选点最优。容易想到重心,但是立刻就被 hack 了。

不服气的我发现重心被 hack 的可能性不大(因为当时没有看到数据捆绑,不过也多亏没看到),然后就开始写,结果发现跑过了大样例?

然后在原代码的基础上稍微修饰一下,再测的时候发现第二个样例挂了,说明假了。有点无奈,所以分段跑一下以后就丢了。

赛后发现有 65pts,某猫告诉我我的链判错了。我尝试改链,然后就:

image

一条链损我 35pts?(以及重心为什么是对的)

纪念一下我的 AC 代码(轻触查看)
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
	int w=1,s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
	return w*s;
}
const int mod=1e9+7;
const int maxn=2e5+10;
const int inf=1e9+7;
int n,k;
vector<int> G[maxn];
int xo[maxn];
int du[maxn];
void Sub()
{
	if(n>=k*2+2)puts("2");
	else if(n>=k+1)puts("1");
	else puts("0");
	return ;
}
int f[maxn][22],d[maxn],fa[maxn],siz[maxn],dp[maxn];
int ans=0;
void pre(int x,int faa)
{
    fa[x]=faa;
	siz[x]=1;
	d[x]=d[faa]+1;
	f[x][0]=faa;
	for(int i=1;i<=21;i++)f[x][i]=f[f[x][i-1]][i-1];
	for(auto y : G[x])
	{
		if(y==faa) continue;
		pre(y,x);
		siz[x]+=siz[y];
	}
}
int lca(int x,int y)
{
	if(d[x]<d[y]) swap(x,y);
	for(int i=21;i>=0;i--)
		if(d[f[x][i]]>=d[y]) x=f[x][i];
	if(x==y) return y;
	for(int i=21;i>=0;i--)
	{
		if(f[x][i]!=f[y][i])
		{
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}
void dfs(int x,int faa)
{
	int ma=0;dp[x]=0;siz[x]=1;
	for(auto y : G[x])
	{
		if(y==faa)continue;
		dfs(y,x);siz[x]+=siz[y];
		ma=max(ma,dp[y]-(siz[y]>=k));
		if(siz[y]>=k)dp[x]++;
	}
	dp[x]+=ma;
}
void Sub2()
{
	pre(1,0);
	for(int x=1;x<=n;x++)
	{
		dfs(x,0);
		int ma=-11,maa=-11,anss=0;
		for(auto y : G[x])if(siz[y]>=k)anss++;
		for(auto y : G[x])
		{
			int num=dp[y];
			if(siz[y]>=k)num--;
			if(num>ma)
			{
                maa=ma;
				ma=num;
			}
			else if(num>maa)
			{
				maa=max(0ll,num);
			}
		}
		anss=anss+ma+maa;
		ans=max(ans,anss);
	}
	printf("%lld\n",ans);
}
int root,ddp[maxn]={inf};
void get(int x,int fa)
{
	siz[x]=1;
	for(auto y : G[x])
	{
		if(y==fa)continue;
        get(y,x);siz[x]+=siz[y];
        ddp[x]=max(ddp[x],siz[y]);
	}
	ddp[x]=max(n-siz[x],ddp[x]);
	if(ddp[root]>ddp[x])root=x;
}
void Sub3()
{
	get(1,0);
	dfs(root,0);
	int ma=-11,maa=-11,x=root,anss=0;
	for(auto y : G[x])if(siz[y]>=k)anss++;
	for(auto y : G[x])
	{
		int num=dp[y];
		if(siz[y]>=k)num--;
		if(num>ma)
		{
			maa=ma;
			ma=num;
		}
		else if(num>maa)
		{
			maa=max(0ll,num);
		}
	}
	anss=anss+ma+maa;
	printf("%lld\n",anss);
}
void Main()
{
	bool sub=1;
	n=read(),k=read();ans=0;root=0;
	for(int i=1;i<=n;i++)G[i].clear();
	for(int i=1;i<=n;i++)du[i]=dp[i]=siz[i]=d[i]=ddp[i]=0; 
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read();
		G[x].push_back(y);
		G[y].push_back(x);
		du[x]++;du[y]++;
		if(du[x]>2||du[y]>2)sub=0;
	}
	if(sub){Sub();return ;}
	if(n<=1000){Sub2();return ;}
	Sub3();return ;
}
signed main()
{
#ifdef Lydic
	freopen(".in","r",stdin);
	freopen(".out","w",stdout);
//  #else
//   	freopen("Zephyros.in","r",stdin);
//   	freopen("Zephyros.out","w",stdout);
#endif  
	int T=read();
	while(T--)Main();
    return 0;

}

转去看 T2,光速写完 20pts 的暴力,然后发现很可以二分,推了一大会发现二分复杂度甚至不如暴力的我决定弃掉这道题。

讲课的人说是笛卡尔树思想,但是我不会单调栈。

赛后发现为数不多的 20pts 还爆了 10pts,只剩一份蛋包饭的分数了。

不知道为什么 T3 当时没有细想,现在觉得比 T2 简单,但是考场上放了个 5pts 就过了。这道题 jsy 讲容斥的时候讲过错排思想,针对这道题就是把排列转成多个环以后跑一个分组背包(昨天刚见过)。

T4 的话觉得是原,把原题扒出来以后发现压根没有一点相似之处,小部分数据可以区间 dp,但是当时我拐回去看 T1 了,所以没有写(然后 T1 也爆了)。

总结

还是细节问题,但有一部分也是数据的原因。总的来说比赛挂了 10+35=45pts,不算高,但也不算低。

排名非常靠后,感觉 7 级线有点难。

posted @ 2024-09-28 16:23  Redamancy_Lydic  阅读(33)  评论(0编辑  收藏  举报