其他分享
首页 > 其他分享> > CF367E Sereja and Intervals

CF367E Sereja and Intervals

作者:互联网

written on 2022-05-06

这题简单,先给这题写题解

套路题,为每个区间分配左右端点,那不就是在长度为 \(m\) 的数轴上任取 \(2n\) 个点吗?然后考虑题目的要求,区间两两不包含。

对于这个要求,我们发现,对于同一数轴上的几个区间,要求不互相包含,在已经确定所有左右端点的情况下,方案数是唯一的。证明不难,可以参照有图的这篇题解(鸣谢@cqh91)。

这下题目就转化成了一个简单的问题,即:在长度为 \(m\) 的数轴上任取 \(n\) 个左端点, \(n\) 个右端点的方案数。考虑 dp ,一个位置有四种决策。

  1. 只是左端点

  2. 只是右端点

  3. 既是左端点又是右端点

  4. 什么都不是

转移显然,然后对于另一个 至少存在一个区间的左端点等于 \(x\) 的限制 ,只要在转移时稍加变化即可。因为可以无序,最后乘以阶乘就好。

#include<bits/stdc++.h>
#define N 320
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int n,m,L;
ll f[2][N][N];
int main()
{
	scanf("%d%d%d",&n,&m,&L);
	//选出2n个点,n个左端点,n个右端点
	//可以证明左右端点配对方案唯一,证明略
	//那么原题转化为在区间1~m中选出2n个点的方案数
	//决策:对于每一个点,可以是
	/*
	1.只是左端点
	2.只是右端点 
	3.什么都不是
	4.既是左端点又是右端点 
	(i==L特殊转移)
	*/
	//状态:需要记录位置(滚动)、左端点个数、右端点个数 
	if(n>m) printf("0"),exit(0); 
	f[0][0][0]=1;
	for(int i=1;i<=m;i++)
	{
		for(int j=0;j<=min(i,n);j++)
		{
			for(int k=0;k<=min(j,n);k++)
			{
				f[i&1][j][k]=0;
				if(i==L)
				{
					if(j) f[i&1][j][k]=(f[i&1][j][k]+f[i-1&1][j-1][k])%mod;
					if(j&&k) f[i&1][j][k]=(f[i&1][j][k]+f[i-1&1][j-1][k-1])%mod;
					continue;
				}
				if(j) f[i&1][j][k]=(f[i&1][j][k]+f[i-1&1][j-1][k])%mod;
				if(k) f[i&1][j][k]=(f[i&1][j][k]+f[i-1&1][j][k-1])%mod;
				if(j&&k) f[i&1][j][k]=(f[i&1][j][k]+f[i-1&1][j-1][k-1])%mod;
				f[i&1][j][k]=(f[i&1][j][k]+f[i-1&1][j][k])%mod;
//				printf("i=%d j=%d k=%d val=%lld\n",i,j,k,f[i&1][j][k]);
			}
		}
	}
	//time O(n*n*m)    memory O(n*m)
	ll jc=1;
	for(int i=1;i<=n;i++) jc=jc*i%mod;
	printf("%lld",f[m&1][n][n]*jc%mod);
}

标签:2n,数轴,int,ll,Intervals,端点,CF367E,Sereja,个点
来源: https://www.cnblogs.com/Freshair-qprt/p/16537761.html