Weird LIS
题解
英文题解的长篇大论贞德很难看懂耶,又没找到中文题解┭┮﹏┭┮
我们考虑怎样的序列
A
A
A可能会是合法的,即拥有对应的排列。
我们设
K
=
max
i
=
1
n
A
i
K=\max_{i=1}^{n}A_{i}
K=maxi=1nAi,显然有
∀
i
∈
[
1
,
n
]
,
A
i
∈
[
K
−
1
,
K
]
\forall i\in[1,n],A_{i}\in[K-1,K]
∀i∈[1,n],Ai∈[K−1,K]。
我们先定义两类点,分别是必需点与非必需点,从名称上应该比较好理解。
显然,非必需点要么不在我们的最长上升子序列中,要么有其它点可以与之发挥等效的价值。
而必需点则是没有其他点能够发挥等效价值的,去掉它就意味着我们最长上升子序列长度的减小。
我们先对于所有
A
A
A的情况都相同的情况单独论证一下。
这种情况意味着要么我们所有点都是必需点,要么所有点都是非必需点。
所有点都是必需点的情况显然就是一个
{
1
,
2
,
3
,
4
,
.
.
.
,
n
}
\{1,2,3,4,...,n\}
{1,2,3,4,...,n}的序列,这种情况下,所有
A
A
A都是等于
n
−
1
n-1
n−1的。
而所有点都是非必需点的情况,那么每一个点都必然有至少一个可与之替换的点,所以我们的
K
⩽
⌊
n
2
⌋
K\leqslant \lfloor\frac{n}{2}\rfloor
K⩽⌊2n⌋。
这样的一个序列我们也还是相当容易构造出来的,像
{
n
−
K
+
1
,
n
−
K
+
2
,
.
.
.
,
n
,
n
−
2
K
+
1
,
n
−
2
K
+
2
,
.
.
.
}
\{n-K+1,n-K+2,...,n,n-2K+1,n-2K+2,...\}
{n−K+1,n−K+2,...,n,n−2K+1,n−2K+2,...}就可以构造出来了。
那么我们下面就只需要讨论
K
K
K与
K
−
1
K-1
K−1都在我们的
A
A
A序列中出现了的情况了。
显然,在这种情况下,我们的
K
K
K是可以表示我们整个序列的最长上升子序列长度的,由于必然有一个点不在我们的最长上升子序列中,去掉这个点,必然不影响我们最长上升子序列的长度,所以必然能取到。
而我们的
A
=
K
−
1
A=K-1
A=K−1的点都是必然在我们的最长上升子序列中的,也就是我们的必需点,
A
=
K
A=K
A=K的点去掉后也不会影响,也就是我们的非必需点。
显然,我们的每一个
A
=
K
−
1
A=K-1
A=K−1的点都会为我们的最长上升子序列贡献
1
1
1的长度,记其数量为
K
1
K_1
K1,显然,
K
K
K必然是不小于
K
1
K_1
K1的。
而我们
A
=
K
−
2
A=K-2
A=K−2的点有可能为我们的最长上升子序列贡献长度。
我们记可以把所有
A
=
K
A=K
A=K的点的位置看成被
A
=
K
−
1
A=K-1
A=K−1的点拆分开的连续段。
对于一个连续段,如果该连续段的左右边的
A
=
K
−
1
A=K-1
A=K−1的点的权值为
L
L
L与
R
R
R的话(边界我们可以看成极值),那么这个连续段的点只有在选到
[
L
,
R
]
[L,R]
[L,R]中时才可能对我们的
K
K
K产生贡献。
在某个长度上产生贡献的点必然是成对存在的,这也意味着如果一个长度为
l
e
n
len
len的连续段,产生的贡献最大为
⌊
l
e
n
2
⌋
\lfloor\frac{len}{2}\rfloor
⌊2len⌋。
如果我们有
m
m
m个连续段,长度分别为
Q
1
,
Q
2
,
.
.
.
,
Q
m
Q_1,Q_2,...,Q_m
Q1,Q2,...,Qm,我们记
K
2
=
∑
i
=
1
m
⌊
Q
i
2
⌋
K_2=\sum_{i=1}^{m}\lfloor\frac{Q_i}{2}\rfloor
K2=∑i=1m⌊2Qi⌋。
显然,我们的
K
K
K的范围限制,
K
∈
[
K
1
,
K
1
+
K
2
]
K\in[K_1,K_1+K_2]
K∈[K1,K1+K2]。
我们考虑我们去证明我们是否能对所有满足上面的条件的序列都构造出一种合法的排列。
我们其实去构造一下就知道了,应该是比较好想到的。
我们可以考虑将我们的
A
=
K
−
1
A=K-1
A=K−1的位置提出来,形成新的序列。
我们先将与我们最长上升子序列无关的的部分填上去,显然,我们有一种方法是将前面的一部分与后面的一部分填满,设前面填了
L
L
L个,后面填了
R
R
R个。
那么对于前面,我们可以依次这样填
{
n
,
n
−
1
,
n
−
2
,
.
.
.
,
n
−
L
+
1
}
\{n,n-1,n-2,...,n-L+1\}
{n,n−1,n−2,...,n−L+1},而对于后面,我们可以依次这样填
{
R
,
R
−
1
,
.
.
.
,
1
}
\{R,R-1,...,1\}
{R,R−1,...,1}。
显然,这种前面的会影响我们的最长上升子序列当且仅当它填到倒数第二个必需点的后面去了;
而后面这部分会影响我们的最长上升子序列当且仅当它填到正数第二个必需点的前面么去了。
如果我们这样填的话,产生冲突的只有我们总共只有两个必需点的情况。
但并不是所有两个必需点的情况都会产生影响,由于我们可能虽然只有两个必需点,但我们中间还有可能有一部分要产生贡献的点,将中间这段区间分开,我们还可以根据这部分点将其分开。
如果我们连这部分点都没有了,说明我们的最长公共子序列长度必然为
2
2
2,但我们的
A
⩾
2
A\geqslant 2
A⩾2,
K
−
1
=
1
K-1=1
K−1=1,不可能在
A
A
A中出现,也就不需要考虑了。
既然我们已经将前一半与后一半都填满了,中间空出来了一部分区间,留给我们想贡献给答案的非必需点的。
我们可以把这部分点和我们的必需点合成一个序列看,在这上面填。
对于必需点在这个序列上将我们的费必需点序列分成若干个不相交区间,如果一个长度为
n
′
n'
n′的区间贡献为
k
k
k,我们可以这样填,假设填的数从
1
1
1开始,
{
n
−
k
+
1
,
n
−
k
+
2
,
.
.
.
,
n
,
n
−
2
k
+
1
,
n
−
2
k
+
2
,
.
.
.
,
n
−
k
,
n
−
3
k
+
1
,
.
.
.
,
1
,
.
.
.
}
\{n-k+1,n-k+2,...,n,n-2k+1,n-2k+2,...,n-k,n-3k+1,...,1,...\}
{n−k+1,n−k+2,...,n,n−2k+1,n−2k+2,...,n−k,n−3k+1,...,1,...}。
显然,这部分数的取值范围都在该区间两侧的必需点数的区间内的。
如果直接这样想的可能不太好填,我们可以考虑就那个
c
n
t
cnt
cnt当指针一个一个放进去之类的,反正整个序列的数都在我们都在没贡献的区间内啦!
还是举例说明吧 ,我终于明白为什么官解都认为自己讲不清楚了,就用官方题解给出的序列
A
=
{
4
,
5
,
5
,
5
,
4
,
5
,
5
,
5
,
5
,
5
,
4
,
5
,
5
}
.
A=\{4,5,5,5,4,5,5,5,5,5,4,5,5\}.
A={4,5,5,5,4,5,5,5,5,5,4,5,5}.我们先填好序列
P
P
P中对答案没影响的部分,得到
P
=
{
?
,
13
,
12
,
11
,
?
,
?
,
?
,
?
,
?
,
2
,
1
}
P=\{?,13,12,11,?,?,?,?,?,2,1\}
P={?,13,12,11,?,?,?,?,?,2,1}再将我们的必需点填进去,显然两个必需点之间的差值是区间中现在还是
?
?
?的非必需点的数量,
P
=
{
3
,
13
,
12
,
11
,
4
,
?
,
?
,
?
,
?
,
?
,
10
,
2
,
1
}
P=\{3,13,12,11,4,?,?,?,?,?,10,2,1\}
P={3,13,12,11,4,?,?,?,?,?,10,2,1}中间再按我们上面的方法填,得到:
P
=
{
3
,
13
,
12
,
11
,
4
,
8
,
9
,
6
,
7
,
5
,
10
,
2
,
1
}
P=\{3,13,12,11,4,8,9,6,7,5,10,2,1\}
P={3,13,12,11,4,8,9,6,7,5,10,2,1}这就构造出一种合法的方案了。
我相信大家通过这个样例和上面讲解都已经充分的理解了我们的构造方法了,如果没看懂的话就再看几遍吧。
于是我们就证明了如果我们的
K
∈
[
K
1
,
K
1
+
K
2
]
K\in[K_1,K_1+K_2]
K∈[K1,K1+K2],就一定能够构造出一种合法的方案。
但我们的目的是求出我们总的方案数,考虑这东西怎么弄。
由于每个
K
K
K对于固定的
K
1
,
K
2
K_1,K_2
K1,K2其取值范围也是固定的,也就是说对于一个必需点位置与非必需点位置固定的序列,我们的
K
1
,
K
2
K_1,K_2
K1,K2也是固定的,其
K
K
K便是固定的。
我们可以考虑枚举我们的
K
1
K_1
K1与
K
2
K_2
K2,求出它能构造出多少个序列,乘上它
K
K
K的范围限制。
如果我们总共有
x
x
x个必需点,和
y
y
y个非必需点对,我们要做的相当于要将这
y
y
y个必需点对插入到必需点间,当然,它们自身是无序的,这也就很好用隔板法了,从
x
+
y
x+y
x+y个点中选出
x
x
x个充当我们的必需点,而没被选的就是非必需点对,将其展开就可得到一个序列。
但我们的
x
+
2
y
x+2y
x+2y不一定等于
n
n
n,由于我们求
K
2
K_2
K2的部分是下取整的,我们要把
n
−
x
−
2
y
n-x-2y
n−x−2y个单独出来的点放到非必需点的连续区间中去(这里也包括那些空区间),总共有
x
+
1
x+1
x+1个区间,所以是
(
x
+
1
n
−
x
−
2
y
)
\binom{x+1}{n-x-2y}
(n−x−2yx+1)。
再加上
[
max
(
2
,
x
)
,
min
(
y
,
m
)
]
[\max(2,x),\min(y,m)]
[max(2,x),min(y,m)]的范围,我们的答案便应当为:
∑
i
=
1
min
(
n
−
1
,
m
)
∑
j
=
0
n
(
i
+
1
n
−
i
−
2
j
)
(
i
+
j
i
)
(
min
(
i
+
j
,
m
)
−
max
(
i
−
1
,
2
)
)
\sum_{i=1}^{\min(n-1,m)}\sum_{j=0}^{n}\binom{i+1}{n-i-2j}\binom{i+j}{i}(\min(i+j,m)-\max(i-1,2))
i=1∑min(n−1,m)j=0∑n(n−i−2ji+1)(ii+j)(min(i+j,m)−max(i−1,2))
时间复杂度
O
(
n
2
)
O\left(n^2\right)
O(n2),由于模数是输入的,组合数需要递推处理。
一些惊喜
我不认为有人类做得来。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 5005
#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 INF=0x3f3f3f3f;
const int mo=993244853;
const int inv2=499122177;
const double jzm=0.997;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,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');}
int gcd(int a,int 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;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,m,mod,C[MAXN][MAXN],ans;
void init(){
for(int i=1;i<=n;i++){
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++)
C[i][j]=add(C[i-1][j-1],C[i-1][j],mod);
}
}
signed main(){
read(n);read(m);read(mod);init();
ans=min(m,n/2)-1+(m==n-1);
for(int i=1;i<=min(n-1,m);i++)
for(int j=max(0,(n-i-i)/2);i+j+j<=n;j++)if(i+j>2)
Add(ans,1ll*C[i+1][n-i-j-j]*C[i+j][i]%mod*(min(i+j,m)-max(i-1,2))%mod,mod);
printf("%d\n",ans);
return 0;
}