您的位置:首页 > 其它

CodeForces 380 D.Sereja and Cinema(组合数学)

2018-01-07 09:59 295 查看
Description

电影院有n位置,每个位置两边都有一个放水杯的槽,相邻两个位置分享同一个槽,看电影的人按顺序进场,先进场的人会把其座位两边没人用的槽都占了,如果一个人进场后发现其座位两边槽都被占了就会不满意,现在给出一部分位置的人进场的顺序,要求给没确定进场顺序的位置安排进场顺序使得所有看电影的人都很满意,问方案数

Input

第一行一整数n表示位置数,之后输入n个整数ai,若ai=0说明坐在第i个位置的 人的进场顺序还没确定,若ai≠0说明坐在第i个位置的人是第ai个进场的(1≤n≤105)

Output

输出方案数,结构模109+7

Sample Input

11

0 0 0 0 0 0 0 0 0 0 0

Sample Output

1024

Solution

第一个进场的人会占两个槽,后面的人要想每人至少一个槽就只能一人一个,也就是说后面进场的人必须坐在一个之前进场的人的旁边,把所有进场顺序确定的位置按(位置pos,进场顺序val)存下来,按进场顺序排序升序排

分两种情况考虑,第一个进场的人位置没有确定,第一个进场的人位置已经确定。如果第一个进场的人位置没有确定,就枚举其位置,故只要求出第一个进场的人位置确定时的方案数即可

按进场顺序一个个将已经确定顺序的人放进去,假设当前已经坐满的位置区间为[l,r],初始时l,r均为第一个进场的人的位置,然后按已经排好序的(位置,进场顺序)把这些进场顺序确定的人放好,假设当前人第val个进场,要坐在第pos个位置,上一个(确定顺序的)进场的人是第pre个进场的,那么这两个人之间有val−pre−1个人,如果pos在[l,r]之间显然不行,一个位置只能坐一个人,只考虑pos<l的情况,pos>r的情况类似,这val−pre−1个人进场时只有两个选择,从l开始往左扩展,从r开始往右扩展,且往左需要扩展到第pos+1个位置,这样第val个进场的人才能坐在第pos个位置,故如果val−pre−1<l−pos−1就无解,否则可以从这些人中选出l−pos−1个人从l往pos扩展,剩下的人就按进场顺序以此从r往右坐,方案数Cl−pos−1val−pre−1,然后更新l为pos,更新r为r+(val−pre−1)−(l−pos−1)

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=100005;
#define mod 1000000007
int fact[maxn],inv[maxn];
void init(int n=1e5)
{
fact[0]=1;
for(int i=1;i<=n;i++)fact[i]=(ll)i*fact[i-1]%mod;
inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=mod-(ll)(mod/i)*inv[mod%i]%mod;
inv[0]=1;
for(int i=1;i<=n;i++)inv[i]=(ll)inv[i-1]*inv[i]%mod;
}
int C(int n,int m)
{
return (ll)fact
*inv[m]%mod*inv[n-m]%mod;
}
struct node
{
int pos,val;
bool operator<(const node&b)const
{
return val<b.val;
}
}a[maxn];
void add(int &x,int y)
{
x=x+y>=mod?x+y-mod:x+y;
}
int n,m;
int Solve(int pos,int i)
{
int l=pos,r=pos,ans=1,pre=1;
for(;i<m;i++)
{
if(a[i].pos<l)
{
int dval=a[i].val-pre-1,dpos=l-a[i].pos-1;
if(dpos>dval)return 0;
ans=(ll)ans*C(dval,dpos)%mod;
l=a[i].pos,r+=dval-dpos,pre=a[i].val;
}
else if(a[i].pos>r)
{
int dval=a[i].val-pre-1,dpos=a[i].pos-r-1;
if(dpos>dval)return 0;
ans=(ll)ans*C(dval,dpos)%mod;
r=a[i].pos,l-=dval-dpos,pre=a[i].val;
}
else return 0;
}
return ans;
}
int main()
{
init();
while(~scanf("%d",&n))
{
m=0;
for(int i=1;i<=n;i++)
{
int temp;
scanf("%d",&temp);
if(temp)a[m++]=(node){i,temp};
}
a[m++]=(node){n+1,n+1};
sort(a,a+m);
int ans=0;
if(a[0].val==1)add(ans,Solve(a[0].pos,1));
else
for(int i=1;i<=n;i++)add(ans,Solve(i,0));
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: