CF367E Sereja and Intervals
作者:互联网
written on 2022-05-06
这题简单,先给这题写题解
套路题,为每个区间分配左右端点,那不就是在长度为 \(m\) 的数轴上任取 \(2n\) 个点吗?然后考虑题目的要求,区间两两不包含。
对于这个要求,我们发现,对于同一数轴上的几个区间,要求不互相包含,在已经确定所有左右端点的情况下,方案数是唯一的。证明不难,可以参照有图的这篇题解(鸣谢@cqh91)。
这下题目就转化成了一个简单的问题,即:在长度为 \(m\) 的数轴上任取 \(n\) 个左端点, \(n\) 个右端点的方案数。考虑 dp ,一个位置有四种决策。
-
只是左端点
-
只是右端点
-
既是左端点又是右端点
-
什么都不是
转移显然,然后对于另一个 至少存在一个区间的左端点等于 \(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