[JOISC 2020 Day2] 遗迹

一、题目

点此看题

二、解法

首先理解删除的过程,可以按值域从高到低扫描。可以维护一个堆,每次向堆中加入两个初始值为 i 的位置,然后取出堆中最大的位置,钦定它为高度 i 并且可以保留到最后。

这样还不是特别好做,考虑切换限制主体得到更多性质。我们按位置从后到前扫描,维护一个还未出现过的集合 S,假设现在遇到元素的高度是 hi,那么我们取出 Shi 的最大值(若不存在视为 0),作为这个位置最终的值。

那么从后往前 dp,考虑记录一段连续的被取出的前缀,可以用类似 MEX counting 的状态定义和转移方法。设 f[i][j] 表示考虑后 i 个位置,S 中被取出的最大前缀是 j 的方案数,设以前的位置有 c0 个位置钦定消失,有 c1 个位置钦定出现。

为了方便转移,把相同高度的元素染色(视为不同),最后再除以 2n 就得到了答案。

若当前位置钦定消失,则值肯定不能超过 j,以前钦定出现了用了 j 个,钦定消失了用了 c0 个,可用的位置数量是 2jjc0=jc0,所以:f[i][j]f[i1][j](jc0)

若当前位置钦定出现,分两种情况讨论:

  • 如果最后的值 >j+1,那么延后考虑这个位置的取值:f[i][j]f[i1][j]
  • 如果最后的值 =j+1,枚举前缀的变化量 k,那么这个位置的取值有 2k(k1)=k+1 个。选择 k1 个元素出现位置的方案数是 (c1jk1),那么:f[i][j+k]f[i1][j]G[k1](k+1)(c1jk1)

其中 G[i] 的含义为可用 i 种初始高度,要求生成最后 i 个高度连续元素的方案数。设 g[i][j] 表示用了 i 种初始高度,填满了 j 个位置,那么 G[i]=g[i][i],转移的限制是:

  • 每种高度只能用最多两次。
  • 要一直满足 ij,即填多了位置是不合法的。

那么可以写出转移 g[i][j]=g[i1][j]+g[i1][j1]2j+g[i1][j2]j(j1)

时间复杂度 O(n3)

#include <cstdio>
const int M = 1205;
const int MOD = 1e9+7;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,a[M],g[M][M],f[M][M],C[M][M];
void add(int &x,int y) {x=(x+y)%MOD;}
signed main()
{
	n=read();m=n<<1;
	for(int i=1;i<=n;i++) a[read()]=1;
	for(int i=0;i<=m;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
	}
	g[0][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=0;j<=i;j++)
		{
			g[i][j]=g[i-1][j];
			if(j>0) add(g[i][j],2*j*g[i-1][j-1]);
			if(j>1) add(g[i][j],j*(j-1)*g[i-1][j-2]);
		}
	f[m+1][0]=1;
	for(int i=m,c0=0,c1=0;i>=1;i--)
	{
		if(a[i])
		{
			c1++;
			for(int j=c0;j<=c1-1;j++)
			{
				add(f[i][j],f[i+1][j]);
				for(int k=1;k<=c1-j;k++)
					add(f[i][j+k],f[i+1][j]*C[c1-j-1][k-1]
					%MOD*g[k-1][k-1]%MOD*(k+1));
			}
		}
		else
		{
			c0++;
			for(int j=c0;j<=c1;j++)
				add(f[i][j],f[i+1][j]*(j-c0+1));
		}
	}
	int ans=f[1][n],inv2=(MOD+1)/2;
	for(int i=1;i<=n;i++) ans=ans*inv2%MOD;
	printf("%lld\n",ans);
}
posted @   C202044zxy  阅读(351)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
历史上的今天:
2021-06-11 Educational Codeforces Round 110 (Rated for Div. 2)
点击右上角即可分享
微信分享提示