​传送门​

设第一个数字是 x x x,暂时不关注这个 x x x是几,只关注相对大小,我们往后看

n o w now now是当前最大最小值间还有几个数的空位

如果 a [ i ] = = a [ i − 1 ] a[i]==a[i-1] a[i]==a[i−1],显然此时应该插入在空位之间

a n s = a n s ∗ n o w , n o w − − ans = ans*now,now-- ans=ans∗now,now−−

如果 a [ i ] > a [ i − 1 ] a[i]>a[i-1] a[i]>a[i−1],此时插入的数要么比最小值小 a [ i ] − a [ i − 1 ] a[i]-a[i-1] a[i]−a[i−1],要么比最大值大 a [ i ] − a [ i − 1 ] a[i]-a[i-1] a[i]−a[i−1]

也就是有两种相同的插入方式使得 n o w now now增加相同值

a n s = a n s ∗ 2 , n o w + = ( a [ i ] − a [ i − 1 ] − 1 ) ans = ans*2,now+=(a[i]-a[i-1]-1) ans=ans∗2,now+=(a[i]−a[i−1]−1)

那么按照这样插入完 n − 1 n-1 n−1个数后,这 n − 1 n-1 n−1个数必须和第一个数 x x x是连续的

也就是 n o w now now最后变为零,不是零说明无解

自己 y y yy yy出来的,不会证明,不过感觉很正确的样子

update:后来找了下题解,发现确实是std正确的写法

CCPC2019 I. Interesting Permutation(思维)_#define

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9+7;
const int maxn = 2e5+10;
int t,n,a[maxn];
signed main()
{
cin >> t;
while( t-- )
{
cin >> n;
for(int i=1;i<=n;i++) scanf("%lld",&a[i] );
int flag = 1, ans = 1 , now = 0;//中间的数字呢
if( a[1]!=0 ) flag = 0;
for(int i=2;i<=n;i++)
{
if( a[i]<a[i-1] ) flag = 0;
if( a[i]==a[i-1] ) ans = ans*now%mod,now--;
else
{
now += a[i]-a[i-1]-1;
ans = ans*2%mod;
}
}
if( now ) flag = 0;
if( !flag ) ans = 0;
cout << ans << endl;
}
}