cf380D 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 all n 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 modulo 1000000007 (109 + 7).

Input

The first line contains integer n (1 ≤ n ≤ 105). The second line contains n integers, the i-th integer shows either the index of the person (index in the entering queue) with the ticket for the i-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 to n. 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
11
0 0 0 0 0 0 0 0 0 0 0
Output
1024
Input
6
0 3 1 0 0 0
Output
3






给出一个数n还有n个数ci
如果ci>0,表示排列上的第ci个位置上的数为i
如果ci=0,表示排列上的第ci个位置上的数不确定

即是说,有一个n的排列,其中部分position上的数固定,求有多少种排列满足:
对于排列上的任意一个数x,在x之前不同时存在x+1和x-1这2个数的方案数




solution:
这道题主要在于分情况讨论,得到答案
只要发现一个性质,就可以解决问题了
要保证对于任意一个数x,x+1和x-1不同时存在,则x之前的数放在一起刚好是一个[1,n]的子
区间[L,R],这个自区间的长度为x-1,且有is[x] = L - 1 || is[x] = R + 1
这样我们只需要分情况讨论,
部分情况直接推出公式得到答案
部分情况需要用到递推,同时维护当前的L,R
具体看代码

is[i]表示排列的第i个数固定为is[i]
pre[i]表示第i个数前一个被固定的数,没有则为-1
next[i]表示第i个数后一个被固定的数,没有则为-1
f[i]表示当前考虑到排列的第i个数,当前可行的方案数

ps:
这道题初始化f的时候要注意细节,分情况初始化


                                            
  //File Name: cf380D.cpp
  //Author: long
  //Mail: 736726758@qq.com
  //Created Time: 2016年05月20日 星期五 00时32分29秒

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <map>

#define LL long long
#define next NEXT

using namespace std;

const int MAXN = 100000 + 3;
const int MOD = (int)1e9 + 7;

int is[MAXN], pre[MAXN], next[MAXN];
LL f[MAXN],jie[MAXN];

void init(int n){
    jie[0] = 1;
    for(int i=1;i<=n;i++)
        jie[i] = jie[i-1] * i % MOD;
    int now = -1;
    for(int i=1;i<=n;i++){
        pre[i] = now;
        if(is[i]) now = i;
    }
    now = -1;
    for(int i=n;i>0;i--){
        next[i] = now;
        if(is[i]) now = i;
    }
}

LL qp(LL x,LL y){
    LL res = 1;
    while(y){
        if(y & 1) res = res * x % MOD;
        x = x * x % MOD;
        y >>= 1;
    }
    return res;
}

LL get_c(LL x,LL y){
    if(y < 0 || x < y)     return 0;
    if(y == 0 || y == x) return 1;
    return jie[x] * qp(jie[y] * jie[x - y] % MOD,MOD - 2) % MOD;    
}

LL solve(int n,bool flag){
    if(!flag) return qp(2,n - 1);
    init(n);
    //for(int i=1;i<=n;i++){
    //    printf("i = %d is = %d\n",i,is[i]);
    //}
    int L = n + 1, R = 0;
    for(int i=1;i<=n;i++){
        if(!is[i])     continue;
        if(L <= is[i] && R >= is[i]) 
            return 0;
        if(pre[i] == -1 && next[i] == -1){
            LL ans = 0,now;
            for(int x=0;x < is[i];x++){
                now = get_c(i-1,x) * get_c(n-i,is[i]-x-1) % MOD;
                if(x > 1) ans = (ans + now * 2 % MOD) % MOD;
                else ans = (ans + now) % MOD;
            }
            return ans;
        }
        else if(pre[i] > 0){
            f[i] = f[pre[i]];
            //printf("i = %d pre = %d next = %d f = %d\n",i,pre[i],next[i],f[i]);
            if(is[i] > is[pre[i]]) R++;
            else L--;
            //printf("L = %d R = %d\n",L,R);
            if(next[i] == -1){
                return f[i] * get_c(n-i,L-1) % MOD;
            }
            else{
                if(is[next[i]] > R){
                    //printf("i = %d f = %d\n",i,f[i]);
                    f[i] = f[i] * get_c(next[i]-i-1,is[next[i]]-R-1) % MOD;
                    R = is[next[i]] - 1;
                    L = R + 2 - next[i];
                    //printf("i = %d f = %d\n",i,f[i]);
                }
                else{
                    //printf("i = %d f = %d\n",i,f[i]);
                    f[i] = f[i] * get_c(next[i]-i-1,L-is[next[i]]-1) % MOD;
                    L = is[next[i]] + 1;
                    R = L + next[i] - 2;
                    //printf("i = %d f = %d\n",i,f[i]);
                }
            }
            //printf("L = %d R = %d\n",L,R);
        }
        else{
            if(is[i] < is[next[i]]){
                R = is[next[i]] - 1;
                L = R + 2 - next[i];
            }
            else{
                L = is[next[i]] + 1;
                R = L + next[i] - 2;
            }
            int cnt = abs(is[next[i]] - is[i]);
            f[i] = 0;
            if(i == 1){
                f[i] = get_c(next[i]-2,R-is[i]);
            }
            else{
                //printf("is = %d L = %d R = %d\n",is[i],L,R);
                if(i-1 <= is[i]-L)
                    f[i] = qp(2,i-2) * get_c(next[i]-i-1,is[i]-L-i+1) % MOD;
                //printf("f = %d\n",f[i]);
                if(i-1 <= R-is[i])
                    (f[i] += qp(2,i-2) * get_c(next[i]-i-1,R-is[i]-i+1)% MOD) %= MOD;
                //printf("f = %d\n",f[i]);
            }
            //printf("i = %d pre = %d next = %d f = %d\n",i,pre[i],next[i],f[i]);
            //printf("L = %d R = %d\n",L,R);
        }
    }
    return -1;
}

int main(){
    int n,u;
    bool flag = false;
    scanf("%d",&n);
    memset(is,0,sizeof is);
    for(int i=1;i<=n;i++){
        scanf("%d",&u);
        if(u){
            is[u] = i;
            flag = true;
        }
    }
    printf("%d\n",(int)solve(n,flag));
    return 0;
}

 











转载于:https://www.cnblogs.com/-maybe/p/5512893.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值