4.1省选模拟


\(T1\)

\(dis(x,y)=dep(x)+dep(y)-2\times dep(lca(x,y))\)

显然重心最优

然后做一个匹配即可

#define Eternal_Battle ZXK
#include
#define int long long
#define MAXM 200005
#define MAXN 200005
using namespace std;
int head[MAXN],nxt[MAXN],val[MAXN],siz[MAXN],to[MAXN],tot;
int Max[MAXN],Ans,rt,n;
void add(int u,int v,int w)
{
	 tot++;
	 to[tot]=v;
	 val[tot]=w;
	 nxt[tot]=head[u];
	 head[u]=tot;
}
void dfs_rt(int now,int fa)
{
	 siz[now]=1;
	 for(int i=head[now];i;i=nxt[i])
	 {
	 	 int y=to[i];
	 	 if(y==fa) continue;
	 	 dfs_rt(y,now);
	 	 siz[now]+=siz[y];
	 	 Max[now]=max(Max[now],siz[y]);
	 }
	 Max[now]=max(Max[now],n-siz[now]);
	 if(Max[now] In[MAXN];
set Min;
set > Set;
void dfs_vis(int now,int fa,int fg)
{
	 siz[fg]++;
	 In[fg].insert(now);
	 vis[now]=fg;
	 for(int i=head[now];i;i=nxt[i])
	 {
	 	 int y=to[i];
	 	 if(y==fa) continue;
	 	 dfs_vis(y,now,fg);
	 }
}
void Link(int x,int y)
{
//	 cout<<"Link: "<first==n-x+1&&Set.rbegin()->second!=vis[x])
	 {
	 	res=*In[Set.rbegin()->second].begin();
	 }
	 else
	 {
	 	res=vis[*Min.begin()]!=vis[x]||x==rt?*Min.begin():*next(Min.begin());
	 }
	 Link(x,res);
	 return res;
}
signed main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	scanf("%lld",&n);
	for(int i=1,u,v,w;i

\(T2\)

诚不欺我,果然有\(dp\)

\(k<=12\)可以状压,\(m<=4\)那么状态转移数目较少

那么转移易得

\(dp[i][j][S]\)表示我们目前填第\(i\)个数字,已经填了\(j\)个位置,目前大于等于\(i-m\)的位置有哪些的方案数

由于我们是递增填数,就可以实时更新,又因为每个数不同,那么记录一下哪些在原序列里就好了

#include 
#define mod 1000000007
#define MAXN 205
using namespace std;
int n,k,m,Sum;
struct Mat 
{
	int jz[MAXN][MAXN];
	Mat operator * (Mat x) 
	{
		Mat res; 
		memset(res.jz,0,sizeof(res.jz));
		for(int i=0;i<=Sum;i++)
		{
			for(int j=0;j<=Sum;j++)
			{
				for(int k=0;k<=Sum;k++)
				{
					res.jz[i][j]=(res.jz[i][j]+1ll*jz[i][k]*x.jz[k][j])%mod;	
				}
			}
		}
		return res;
	}
}b,St;
int main() 
{
	cin>>n>>k>>m; 
	Sum=k<>=1;
	}
	cout<

\(T3\)

大家都会猜结论\(QAQ,\)谁能教教我怎么猜中啊

考虑交换的中心点必然\(p_i=i\)

然后把\(p_i=i\)去掉,分为若干区间,区间内部值域相等

若出现超过长度为\(3\)的下降子序列就不合法

缩进寄了dk

#include
#define MAXN 600005
using namespace std;
int n,p[MAXN],a[MAXN],Min[MAXN];
int stk[MAXN],top;
int main() 
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    	scanf("%d",&p[i]);
	}
    p[n+1]=n+1,p[0]=0;
    for(int i=1;i<=n;i++) 
	{
        if(p[i-1]!=i-1&&p[i]!=i&&p[i+1]!=i+1)
        {
        	 puts("No");
        	 return 0;
		}
        a[i]=(i==p[i]);
    }
    for(int i=1,j;i<=n;i=j+1)
	{
        for(j=i;j=1;k--)
        {
        	Min[k]=min(Min[k+1],stk[k]);
		}
        int Max=stk[1];
        for(int k=2;k