题目链接
You are running through a rectangular field. This field can be represented as a matrix with 3 rows and m columns. (i, j) denotes a cell belonging to i-th row and j-th column.
You start in (2, 1) and have to end your path in (2, m). From the cell (i, j) you may advance to:
(i - 1, j + 1) — only if i > 1,
(i, j + 1), or
(i + 1, j + 1) — only if i < 3.
However, there are n obstacles blocking your path. k-th obstacle is denoted by three integers ak, lk and rk, and it forbids entering any cell (ak, j) such that lk ≤ j ≤ rk.
You have to calculate the number of different paths from (2, 1) to (2, m), and print it modulo 109 + 7.
题意
给出一个3行m列的矩阵 小人起点在二行一列 中间有m个 占据第ai 行 [l,r] 的障碍物 问你到(2,m) 的方案数有多少。
解题思路:
1. 首先就应该很容易的想到一个dp的递推式。
2. 观察m 发现m巨大 所以肯定是要log级别的复杂度 想到 快速幂优化 O(klog(m/k))
3. 观察得知 障碍物数量与m的最大长度相差巨大, 想到离散化优化空间。O(klog(k))
4. 观察得到障碍物之间可能出现重叠,想到前缀和求区间覆盖。
5. 离散化后 矩阵长度缩减为2*k 达到可以暴力遍历的程度了。遍历矩阵 当每次障碍物覆盖发生变化时 就用矩阵快速幂求一遍当前位置的方案数 然后修改矩阵。总复杂度应该是O(klog(m/k)) 跑了31ms 不清楚那些跑700ms是用什么方法写的。。。
想到方法很容易。。。。 找BUG找了一天。。。 太菜了
重写一遍应该能精简很多,不想写了 写吐了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int MOD=1e9+7;
const int matX = 10;
const int mod = 1e9 + 7;
struct Matrix {
LL n, m, s[matX][matX];
Matrix(int n, int m): n(n), m(m) {
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) s[i][j] = 0;
}
}
Matrix operator*(const Matrix &P)const {
Matrix ret(n, P.m);
for(int i = 0; i < n; i++) {
for(int k = 0; k < m; k++) {
if(s[i][k]) {
for(int j = 0; j < P.m; j++) {
ret.s[i][j] = ((LL)s[i][k] * P.s[k][j] + ret.s[i][j]) % mod;
}
}
}
}
return ret;
}
Matrix operator^(const LL &P)const {
LL num = P;
Matrix ret(n, m), tmp = *this;
for(int i = 0; i < n; i++) ret.s[i][i] = 1;
while(num) {
if(num & 1) ret = ret * tmp;
tmp = tmp * tmp;
num >>= 1;
}
return ret;
}
};
const int MAX=1e4+10;
class Edge {
public:
LL l,r,a;
};
Edge edge[MAX];
int maps[5][MAX<<2];
vector<LL> disper;
void print(Matrix &b) {
for(int i=0; i<3; i++) {
for(int j=0; j<3; j++) {
cout<<b.s[i][j]<<" ";
}
puts("");
}
puts("");
}
int find_key(LL x) {
return lower_bound(disper.begin(),disper.end(),x)-disper.begin();
}
int str[MAX];
bool check(int i){
if(maps[1][i]==0&&maps[1][i-1]!=0){
return 0;
}
if(maps[1][i]!=0&&maps[1][i-1]==0){
return 0;
}
if(maps[2][i]==0&&maps[2][i-1]!=0){
return 0;
}
if(maps[2][i]!=0&&maps[2][i-1]==0){
return 0;
}
if(maps[3][i]==0&&maps[3][i-1]!=0){
return 0;
}
if(maps[3][i]!=0&&maps[3][i-1]==0){
return 0;
}
return 1;
}
int main() {
LL n,m;
scanf("%lld %lld",&n,&m);
for(int i=0; i<n; i++) {
scanf("%lld %lld %lld",&edge[i].a,&edge[i].l,&edge[i].r);
disper.push_back(edge[i].l);
disper.push_back(edge[i].r+1);
}
disper.push_back(1);
disper.push_back(m);
sort(disper.begin(),disper.end());
disper.erase(unique(disper.begin(),disper.end()),disper.end());
// 离散化
for(int i=0; i<n; i++) {
maps[edge[i].a][find_key(edge[i].l)]++;
maps[edge[i].a][find_key(edge[i].r+1)]--;
}
for(int i=1; i<disper.size(); i++) {
for(int j=1; j<=3; j++) {
maps[j][i]+=maps[j][i-1];
}
}
// 前缀和求区间覆盖
Matrix base(3,3);
base.s[0][0]=1,base.s[0][1]=1,base.s[0][2]=0;
base.s[1][0]=1,base.s[1][1]=1,base.s[1][2]=1;
base.s[2][0]=0,base.s[2][1]=1,base.s[2][2]=1;
int per=0;
Matrix ans(3,3);
ans.s[0][0]=0;
ans.s[1][0]=1;
ans.s[2][0]=0;
// 矩阵初始化
for(int i=1; i<disper.size(); i++) {
bool flag=0;
//print(ans);
if(!check(i)||disper[i]==m) {
//cout<<disper[i]<<"fuck"<<disper[per]<<endl;
ans=(base^(disper[i]-disper[per]-1))*ans;
//print(ans);
per=i;
flag=1;
}
if(maps[1][i]>0)
base.s[0][0]=base.s[0][1]=base.s[0][2]=0;
else if(maps[1][i]==0)
base.s[0][0]=1,base.s[0][1]=1,base.s[0][2]=0;
if(maps[2][i]>0)
base.s[1][0]=base.s[1][1]=base.s[1][2]=0;
else if(maps[2][i]==0)
base.s[1][0]=1,base.s[1][1]=1,base.s[1][2]=1;
if(maps[3][i]>0)
base.s[2][0]=base.s[2][1]=base.s[2][2]=0;
else if(maps[2][i]==0)
base.s[2][0]=0,base.s[2][1]=1,base.s[2][2]=1;
if(flag) {
ans=base*ans;
}
}
cout<<ans.s[1][0]<<endl;
}