骗我呢
题解
首先我们可以将原题的模型转化一下。
对于矩阵上的每个点,它是比它右边与右上的两个点小的,而总共有
m
m
m列,
m
+
1
m+1
m+1个取值。
所以我们知道,对于每一行,它最多存在一个点使得这个点的右边的点比这个点大
2
2
2,其它地方都是大
1
1
1。
我们记第
i
i
i行的这个点的列标号为
p
i
p_{i}
pi,很明显,
p
p
p序列满足
∀
i
<
j
,
p
i
+
i
⩽
p
j
+
j
\forall\,i<j, p_{i}+i\leqslant p_{j}+j
∀i<j,pi+i⩽pj+j。
我们相当于要求出满足这个条件的序列数。
这就很容易想到
d
p
dp
dp,我们记
d
p
i
,
j
dp_{i,j}
dpi,j表示选到第
i
i
i个数,
p
i
+
i
=
j
p_{i}+i=j
pi+i=j时的合法方案数。
有转移式,
d
p
i
,
j
=
∑
k
=
i
−
1
j
d
p
i
−
1
,
k
dp_{i,j}=\sum_{k=i-1}^{j}dp_{i-1,k}
dpi,j=k=i−1∑jdpi−1,k
很明显的前缀和结构,转移式再可以被表示为
d
p
i
,
j
=
d
p
i
−
1
,
j
+
d
p
i
,
j
−
1
dp_{i,j}=dp_{i-1,j}+dp_{i,j-1}
dpi,j=dpi−1,j+dpi,j−1
这不就是杨辉三角了吗?由于只有
j
∈
[
i
,
i
+
m
]
j\in[i,i+m]
j∈[i,i+m]的
d
p
dp
dp才有值,所以我们可以联想到卡塔兰数的模型。
我们有两条直线
x
−
y
=
0
x-y=0
x−y=0和
x
−
y
+
m
=
0
x-y+m=0
x−y+m=0,我们走时不能超出这两条直线,也就是走到
x
−
y
−
1
=
0
x-y-1=0
x−y−1=0与
x
−
y
+
m
+
1
=
0
x-y+m+1=0
x−y+m+1=0上,我们的终点是
(
n
+
1
,
n
+
m
+
2
)
(n+1,n+m+2)
(n+1,n+m+2)。
我们分别记这两条直线为
A
A
A与
B
B
B。
由于我们可以从
A
A
A之间
B
B
B相互走,也就是从
A
A
A走到
B
B
B和从
B
B
B走到
A
A
A,我们不能直接求走到这两条直线的方案数,考虑容斥。
也就是说我们的答案为
a
n
s
=
f
−
f
(
A
)
−
f
(
B
)
+
f
(
A
B
)
+
f
(
B
A
)
−
f
(
A
B
A
)
−
f
(
B
A
B
)
+
f
(
A
B
A
B
)
+
f
(
B
A
B
A
)
−
.
.
.
ans=f-f(A)-f(B)+f(AB)+f(BA)-f(ABA)-f(BAB)+f(ABAB)+f(BABA)-...
ans=f−f(A)−f(B)+f(AB)+f(BA)−f(ABA)−f(BAB)+f(ABAB)+f(BABA)−...
但这些答案又该如何求呢?
f
f
f明显是全部从
(
1
,
1
)
(1,1)
(1,1)走到
(
n
+
1
,
n
+
m
+
2
)
(n+1,n+m+2)
(n+1,n+m+2)的方案,也就是
(
2
n
+
m
+
1
n
)
\binom{2n+m+1}{n}
(n2n+m+1)。
而
f
(
A
)
f(A)
f(A)与
f
(
B
)
f(B)
f(B)只要我们将终点沿着
A
A
A与
B
B
B翻折即可。
但对于
A
B
,
B
A
,
A
B
A
,
B
A
B
.
.
.
AB,BA,ABA,BAB...
AB,BA,ABA,BAB...这些呢?
如果我们现在再直线
A
A
A上,走到直线
B
B
B上,相当于我们
x
x
x要比
y
y
y多走
m
+
2
m+2
m+2步。
假设我们原终点是
(
x
,
y
)
(x,y)
(x,y),那么我们此时的新终点应是
(
y
−
m
−
2
,
x
+
m
+
2
)
(y-m-2,x+m+2)
(y−m−2,x+m+2)。
同理可得从
B
B
B走到
A
A
A的新终点是
(
y
+
1
,
x
−
1
)
(y+1,x-1)
(y+1,x−1)。
我们就一直枚举
A
B
A
B
A
.
.
.
ABABA...
ABABA...与
B
A
B
A
B
.
.
.
BABAB...
BABAB...的路径终点,直到走出去为止。
只需要先将组合数预处理后就可以得到答案了。
时间复杂度
O
(
n
+
m
)
O\left(n+m\right)
O(n+m)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 3000005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int mo=1e9+7;
const int jzm=2333;
const int lim=10000000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-9;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,m,dp[MAXN],ans,fac[MAXN],inv[MAXN],f[MAXN];
void init(){
fac[0]=fac[1]=inv[0]=inv[1]=f[1]=1;
for(int i=2;i<=n+n+m+1;i++){
fac[i]=1ll*i*fac[i-1]%mo;
f[i]=1ll*(mo-mo/i)*f[mo%i]%mo;
inv[i]=1ll*f[i]*inv[i-1]%mo;
}
}
int C(int x,int y){if(x<0||y<0||x<y)return 0;return 1ll*fac[x]*inv[y]%mo*inv[x-y]%mo;}
int sakura1(int x,int y);
int sakura2(int x,int y);
int sakura1(int x,int y){if(x<0||y<0)return 0;return add(C(x+y,x),mo-sakura2(y+1,x-1),mo);}
int sakura2(int x,int y){if(x<0||y<0)return 0;return add(C(x+y,x),mo-sakura1(y-m-2,x+m+2),mo);}
signed main(){
read(n);read(m);init();int ans=C(n+n+m+1,n);
ans=add(ans,mo-sakura1(n-1,n+m+2),mo);
ans=add(ans,mo-sakura2(n+m+2,n-1),mo);
printf("%d\n",ans);
return 0;
}