CodeForces Round #223 div.1 D.Sereja and Cinema(组合计数)

来源:互联网 发布:操作系统调度算法代码 编辑:程序博客网 时间:2024/06/16 17:44

D. Sereja and Cinema
time limit per test:1 second
memory limit per test:256 megabytes
input:standard input
output:standard output

The cinema theater hall in Sereja's city is n seats lined up in front of one large screen. There are slots for personal possessions to the left and to the right of each seat. Any two adjacent seats have exactly one shared slot. The figure below shows the arrangement of seats and slots for n = 4.

Today it's the premiere of a movie called "Dry Hard". The tickets for all the seats have been sold. There is a very strict controller at the entrance to the theater, so alln people will come into the hall one by one. As soon as a person enters a cinema hall, he immediately (momentarily) takes his seat and occupies all empty slots to the left and to the right from him. If there are no empty slots, the man gets really upset and leaves.

People are not very constant, so it's hard to predict the order in which the viewers will enter the hall. For some seats, Sereja knows the number of the viewer (his number in the entering queue of the viewers) that will come and take this seat. For others, it can be any order.

Being a programmer and a mathematician, Sereja wonders: how many ways are there for the people to enter the hall, such that nobody gets upset? As the number can be quite large, print it modulo1000000007 (109 + 7).

Input

The first line contains integer n (1 ≤ n ≤ 105). The second line containsn integers, the i-th integer shows either the index of the person (index in the entering queue) with the ticket for thei-th seat or a 0, if his index is not known. It is guaranteed that all positive numbers in the second line are distinct.

You can assume that the index of the person who enters the cinema hall is a unique integer from 1 ton. The person who has index 1 comes first to the hall, the person who has index 2 comes second and so on.

Output

In a single line print the remainder after dividing the answer by number 1000000007 (109 + 7).

Examples
Input
110 0 0 0 0 0 0 0 0 0 0
Output
1024
Input
60 3 1 0 0 0
Output
3



        最近多校什么的,好多方案数的题目,于是无意之中找到一道求方案数的题目做。

        题目背景还是很有意思的,就是一个电影院,每个座位旁边都有两个放杯子的东西。然后现在要看电影的人一个一个排队的进入,每个进入的人对号入座,并且自私的把自己座位边上所有可以占领的放杯子的东西占领,如果某个人没有放杯子的地方,那么他会生气的离开。现在告诉你某些座位的票持有者在排队序列中的位置,问有多少中排队方法使得所有人都不会生气的离开。

       为了使得所有人都有位置可以坐,很显然第一个人可以随便顺序,然后后面的人一定要坐在已经坐人的区间的左边或者右边,即维护一个不断增长的段。那么首先,我们考虑,不知道所有票的持有者在排队顺序中的位置的情况。第一个人可以随便选,我们假设第一个人坐在第i个位置,那么之后的位置可以分为两部分,前一部分为1~i-1,后一部分为i+1~n,我们发现,合法的方案就是把剩下的人分成两个部分,然后按照从小到大的顺序从中间往两边一次坐。如此一来此时的方案数就是C(n-1,i-1)。那么总的方案数就是sigma(C(n-1,i-1))=2^(n-1)。故,当没有其他要求的时候直接输出2^(n-1)。

        然后我们考虑有顺序要求的情况。由于给出的是进场顺序,所以我们先对所有的确定顺序的位置按照出场序排序。如果第一个进场的人是确定的,那么我们直接往下计算。考虑第i个人进场对方案的贡献,假设第i个人的座位编号是j,他的进场序是k,然后我们当前维护的已座座位区间是[l,r](j>r),第i-1个人的进场序是l,那么这个人的贡献相当于从k-l-1个人中取j-r-1个人的方案数,如果j<l则相当于k-l-1个人中取l-j-1个人的方案数。这个很容易理解,分段的计算方案数。然后再维护当前已座座位区间[l,r]。如此拓展即可求出方案数。值得注意的是,我们应该再虚拟一个进场序为n+1,作为编号为n+1的人,这样可以把最后几个进场的人的方案数给确定出来。

        最后,考虑不知道第一个进场的人是谁的情况。这种情况我们只需要枚举任意点作为第一个进场的人,然后将方案数相加即可。具体见代码:

#include<bits/stdc++.h>#define mod 1000000007#define N 100100using namespace std;struct ticket {int nth,id;} a[N];__int64 f[N],ans;__int64 fastpow(__int64 x,int n)//快速幂{    __int64 ret=1;    while (n)    {        if (n&1) ret=ret*x%mod;        x=x*x%mod; n>>=1;    }    return ret;}__int64 c(int n,int m)//费马小的阶乘逆元求组合数{    __int64 ret=1;    ret=ret*f[n]*fastpow(f[m]*f[n-m]%mod,mod-2)%mod;    return ret;}bool cmp(ticket a,ticket b){    return a.nth<b.nth;}int n,tot;__int64 calculate(int x){    __int64 res=1;    int last=1,l=x,r=x,d,m;    int i=1; if (a[i].nth==1) i++;    for(;i<=tot;i++)    {        d=a[i].nth-last-1;//计算当前点与上一个点之间有多少人        if (a[i].id>r)        {            m=a[i].id-r-1;//计算当前点的人的座位与已座区间相差多少个座位            if (d<m) return 0;//如果不可能达到要求则返回0            res=res*c(d,m)%mod;//计算当前点的人的贡献            r=a[i].id; l-=d-m;//维护已座座位区间        } else        {            m=l-a[i].id-1;            if (d<m) return 0;            res=res*c(d,m)%mod;            l=a[i].id; r+=d-m;        }        last=a[i].nth;    }    return res;}int main(){    tot=0; f[0]=1;    scanf("%d",&n);    for(int i=1;i<=100000;i++)        f[i]=f[i-1]*i%mod;    for(int i=1;i<=n;i++)    {        int x;        scanf("%d",&x);        if (x)        {            a[++tot].id=i;            a[tot].nth=x;        }    }    if (tot==0)    {        printf("%I64d\n",fastpow(2,n-1));        return 0;    }    __int64 ans=0;    a[++tot].id=n+1;//虚拟一个进场序为n+1,座位为n+1的人    a[tot].nth=n+1;    sort(a+1,a+1+tot,cmp);    if (a[1].nth==1) ans=calculate(a[1].id);//如果第一个进场的人确定,则直接计算    else for(int i=1;i<=n;i++)//否则枚举第一个进场的人    {        ans+=calculate(i);        if (ans>=mod) ans%=mod;    }    printf("%I64d\n",ans);    return 0;}

阅读全文
0 0