标签:2n 数轴 int ll Intervals 端点 CF367E Sereja 个点
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
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。