Codeforces 102394I Interesting Permutation (脑洞)

I. Interesting Permutation


time limit per test 1 second
memory limit per test 512 megabytes

DreamGrid has an interesting permutation of 1,2,…,n denoted by a1,a2,…,an. He generates three sequences f, g and h, all of length n, according to the permutation a in the way described below:

For each 1≤i≤n, fi=max{a1,a2,…,ai};
For each 1≤i≤n, gi=min{a1,a2,…,ai};
For each 1≤i≤n, hi=fi−gi.
BaoBao has just found the sequence h DreamGrid generates and decides to restore the original permutation. Given the sequence h, please help BaoBao calculate the number of different permutations that can generate the sequence h. As the answer may be quite large, print the answer modulo 10^9+7.

Input
The input contains multiple cases. The first line of the input contains a single integer T (1≤T≤20000), the number of cases.

For each case, the first line of the input contains a single integer n (1≤n≤10^5), the length of the permutation as well as the sequences. The second line contains n integers h1,h2,…,hn (1≤i≤n,0≤hi≤10^9).

It's guaranteed that the sum of n over all cases does not exceed 2*10^6.

Output
For each case, print a single line containing a single integer, the number of different permutations that can generate the given sequence h. Don't forget to print the answer modulo 10^9+7.

Example
input
3
3
0 2 2
3
0 1 2
3
0 2 3
output
2
4
0
Note
For the first sample case, permutations {1,3,2} and {3,1,2} can both generate the given sequence.

For the second sample case, permutations {1,2,3}, {2,1,3}, {2,3,1} and {3,2,1} can generate the given sequence.

题目链接:http://codeforces.com/gym/102394/problem/I

题目大意:定义原排列P为a1,a2,...,an,fi=max{a1,a2,…,ai},gi=min{a1,a2,…,ai},hi=fi−gi,现给出序列h,求满足h的P的个数

题目分析:可以先特判掉3个显然非法的情况:h[0] != 0;h中存在降序;h中存在大于等于n的值

对剩下的情况,考虑h[i]和h[i - 1]的大小,其中若h[i] > h[i - 1],此时要么最大值有更新要么最小值有更新,故将方案数乘2,若h[i]==h[i - 1],则对于第i个数,它必然是1~i中介于最大和最小之间的数,我们称之为中间数,假设中间数有num个,我们要做的就是把答案乘上num,现在问题就是怎么求得num,其实当h[i] > h[i - 1]时,它们的差值(h[i] - h[i - 1] - 1)就是加上h[i]后新增的中间数的个数,减1是因为要将h[i]自身除去

#include <cstdio>
#define ll long long
using namespace std;
int const MAX = 1e5 + 5;
int const MOD = 1e9 + 7;
int n, T, h[MAX];

int main() {
    scanf("%d", &T);
    while (T--) {
        bool ok = true;
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%d", &h[i]);
        }
        ok = h[0] == 0;
        for (int i = 1; ok && i < n; i++) {
            if (h[i] >= n) {
                ok = false;
            }
            if (h[i] < h[i - 1]) {
                ok = false;
            }
        }
        if (!ok) {
            printf("0\n");
            continue;
        }
        ll ans = 1, num = 0;
        for (int i = 1; i < n; i++) {
            if (h[i] > h[i - 1]) {
                ans = (ans << 1) % MOD;
                num += h[i] - h[i - 1] - 1;
            } else {
                ans = (ans * num) % MOD;
                num--;
            }
        }
        printf("%lld\n", ans);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值