链接:https://codeforces.com/contest/954/problem/F
难度:*2100
标签:dp
matrices
sortings
考虑朴素的DP,在不存在障碍的情况下:
{
f
[
i
]
[
0
]
=
f
[
i
−
1
]
[
0
]
+
f
[
i
−
1
]
[
1
]
f
[
i
]
[
1
]
=
f
[
i
−
1
]
[
0
]
+
f
[
i
−
1
]
[
1
]
+
f
[
i
−
1
]
[
2
]
f
[
i
]
[
2
]
=
f
[
i
−
1
]
[
1
]
+
f
[
i
−
1
]
[
2
]
\begin{cases} f[i][0]=f[i-1][0]+f[i-1][1] \\ f[i][1]=f[i-1][0]+f[i-1][1]+f[i-1][2] \\ f[i][2]=f[i-1][1]+f[i-1][2] \end{cases}
⎩
⎨
⎧f[i][0]=f[i−1][0]+f[i−1][1]f[i][1]=f[i−1][0]+f[i−1][1]+f[i−1][2]f[i][2]=f[i−1][1]+f[i−1][2]
由于
N
N
N 范围不大,而
M
M
M 有
1
0
18
10^{18}
1018,所以使用矩阵乘法
考虑没有障碍物的时候,可以构造如下矩阵:
1
1
0
1
1
1
0
1
1
\begin{matrix} 1 & 1 & 0 \\ 1 & 1 & 1 \\ 0 & 1 & 1 \end{matrix}
110111011
然后 矩阵快速幂 就行了
如果某一行出现障碍物,实际上是将该列的矩阵的值全部变为0
然后可以把每一段离散化建立矩阵,分段矩阵乘法
Note:注意若从前向后计算出每一段的最后矩阵
t
t
t 后,
一定是
a
n
s
=
t
∗
a
n
s
ans=t * ans
ans=t∗ans 而不是
a
n
s
=
a
n
s
∗
t
ans=ans * t
ans=ans∗t
上代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
const int maxn=200005;
struct Matrix{
int v[5][5];
void clear(){
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
v[i][j]=0;
}
}
}
void init(){
clear();
v[1][1]=v[2][2]=v[3][3]=1;
}
void reset(){
clear();
v[1][1]=v[1][2]=1;
v[2][1]=v[2][2]=v[2][3]=1;
v[3][2]=v[3][3]=1;
}
Matrix operator *(Matrix b){
Matrix ret;
ret.clear();
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
for(int k=1;k<=3;k++){
ret.v[i][j]=(ret.v[i][j]+v[i][k]*b.v[k][j]%mod)%mod;
}
}
}
return ret;
}
};
Matrix calc(Matrix a,int b){
Matrix ret;
ret.init();
while(b!=0){
if(b%2==1){
ret=ret*a;
}
a=a*a;
b>>=1;
}
return ret;
}
int n,m;
int v[maxn],L[maxn],R[maxn];
int num[5][maxn];
int cur[5];
int obs[maxn];
int kd;
Matrix ans;
int32_t main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>v[i]>>L[i]>>R[i];
obs[++kd]=L[i]-1;
obs[++kd]=R[i];
}
obs[++kd]=1;
obs[++kd]=m;
sort(obs+1,obs+1+kd);
kd=unique(obs+1,obs+kd+1)-obs-1;
for(int i=1;i<=n;i++){
int li=lower_bound(obs+1,obs+kd+1,L[i])-obs;
int ri=lower_bound(obs+1,obs+kd+1,R[i])-obs;
num[v[i]][li]++;
num[v[i]][ri+1]--;
}
ans.clear();
ans.v[2][1]=1;
for(int i=2;i<=kd;i++){
int len=obs[i]-obs[i-1];
Matrix x;
x.reset();
for(int j=1;j<=3;j++){
cur[j]+=num[j][i];
if(cur[j]!=0){
x.v[j][1]=0;
x.v[j][2]=0;
x.v[j][3]=0;
}
}
x=calc(x,len);
ans=x*ans;
}
cout<<ans.v[2][1]<<endl;
return 0;
}