题面
题解
我们令
d
(
i
)
d(i)
d(i) 为
i
i
i 位置前比
a
i
a_i
ai? 大的数个数,我们想要的就是
∑
i
=
1
n
d
(
i
)
\sum_{i=1}^n d(i)
∑i=1n?d(i) 。
然而我们只能得到
∑
i
=
1
n
max
?
(
i
?
a
i
,
0
)
\sum_{i=1}^n \max(i-a_i,0)
∑i=1n?max(i?ai?,0) 。
但是不难发现
d
(
i
)
≥
max
?
(
i
?
a
i
,
0
)
d(i)\geq \max(i-a_i,0)
d(i)≥max(i?ai?,0) 。
所以我们要让两个求和相等,就必须让每个位置的
d
(
i
)
=
max
?
(
i
?
a
i
,
0
)
d(i)=\max(i-a_i,0)
d(i)=max(i?ai?,0) 。把这个条件翻译一下,就是说,每个数前面要么不存在比它大的数,要么存在所有比它小的数。
我们可以考虑从左往右向排列中填数,那么每次只有两种选择,其一是填入比最大值大的一个数,其二是填入 前缀集合
∪
{
0
}
\cup\{0\}
∪{0} 的
m
e
x
\rm mex
mex ,可以利用这个方法判断前
M
M
M 个是否合法。令
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示填了第
i
i
i 个数,最大值为
j
j
j 的方案数,那么
d
p
[
i
]
[
j
]
=
0
????
(
j
<
i
)
d
p
[
i
]
[
j
]
=
d
p
[
i
?
1
]
[
j
]
+
∑
k
<
j
d
p
[
i
?
1
]
[
k
]
dp[i][j]=0~~~~(j<i)\\ dp[i][j]=dp[i-1][j]+\sum_{k<j}dp[i-1][k]
dp[i][j]=0????(j<i)dp[i][j]=dp[i?1][j]+k<j∑?dp[i?1][k]
这样其实不好做,我们令
s
u
m
[
i
]
[
j
]
=
∑
k
=
1
j
d
p
[
i
]
[
k
]
sum[i][j]=\sum_{k=1}^j dp[i][k]
sum[i][j]=∑k=1j?dp[i][k] ,那么
s
u
m
[
i
]
[
j
]
=
s
u
m
[
i
]
[
j
?
1
]
+
(
s
u
m
[
i
?
1
]
[
j
]
?
s
u
m
[
i
?
1
]
[
j
?
1
]
)
+
s
u
m
[
i
?
1
]
[
j
?
1
]
=
s
u
m
[
i
]
[
j
?
1
]
+
s
u
m
[
i
?
1
]
[
j
]
sum[i][j]=sum[i][j-1]+(sum[i-1][j]-sum[i-1][j-1])+sum[i-1][j-1]\\ =sum[i][j-1]+sum[i-1][j]
sum[i][j]=sum[i][j?1]+(sum[i?1][j]?sum[i?1][j?1])+sum[i?1][j?1]=sum[i][j?1]+sum[i?1][j]
最后这个式子非常美观,以至于很容易想到网格图上行走。
s
u
m
[
x
]
[
y
]
→
{
s
u
m
[
x
+
1
]
[
y
]
s
u
m
[
x
]
[
y
+
1
]
sum[x][y]\rightarrow \begin{cases} sum[x+1][y]\\ sum[x][y+1] \end{cases}
sum[x][y]→{sum[x+1][y]sum[x][y+1]?
我们把前
M
M
M 个判断后,可以得到最大值
m
x
mx
mx ,那么最终的答案就是从
(
M
,
m
x
)
(M,mx)
(M,mx) 右走或上走走到
(
N
,
N
)
(N,N)
(N,N) ,中途不越过
x
=
y
x=y
x=y (保持
y
≥
x
y\geq x
y≥x)的方案数。用两个组合数就好了:
C
(
2
N
?
M
?
m
x
,
N
?
M
)
?
C
(
2
N
?
M
?
m
x
,
N
?
M
+
1
)
C(2N-M-mx,N-M)-C(2N-M-mx,N-M+1)
C(2N?M?mx,N?M)?C(2N?M?mx,N?M+1)
时间复杂度
O
(
对
1
0
5
的
嘲
讽
)
O(对 10^5 的嘲讽)
O(对105的嘲讽) 。
CODE
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<random>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
int xchar() {
static const int maxn = 1000000;
static char b[maxn];
static int pos = 0,len = 0;
if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
if(pos == len) return -1;
return b[pos ++];
}
LL read() {
LL f = 1,x = 0;int s = getchar();
while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) putchar('-'),x = -x;
return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}
const int MOD = 1000000007;
int n,m,s,o,k;
int fac[MAXN<<1],inv[MAXN<<1],invf[MAXN<<1];
int C(int n,int m) {
if(m < 0 || m > n) return 0;
return fac[n] *1ll* invf[n-m] % MOD * invf[m] % MOD;
}
int a[MAXN];
int c[MAXN];
void addc(int x,int y) {while(x<=n)c[x]+=y,x+=lowbit(x);}
int sum(int x) {int s=0;while(x)s+=c[x],x-=lowbit(x);return s;}
int main() {
freopen("queue.in","r",stdin);
freopen("queue.out","w",stdout);
n = read();m = read();
fac[0]=fac[1]=inv[0]=inv[1]=invf[0]=invf[1]=1;
for(int i = 2;i <= n*2;i ++) {
fac[i] = fac[i-1] *1ll* i % MOD;
inv[i] = (MOD - inv[MOD%i]) *1ll* (MOD/i) % MOD;
invf[i] = invf[i-1] *1ll* inv[i] % MOD;
}
int mx = 0,flag = 1;
for(int i = 1;i <= m;i ++) {
a[i] = read();
mx = max(mx,a[i]);
addc(a[i],1);
if(a[i] != mx) {
if(sum(a[i]) != a[i]) flag = 0;
}
}
if(!flag) return printf("0\n"),0;
int rr = n-m,cc = n-mx;
int ans = (C(rr+cc,rr) +MOD- C(rr+cc,rr+1)) % MOD;
AIput(ans,'\n');
return 0;
}
|