contest link
题目
n ≤ 1 0 5 n \le 10^5 n≤105 对应前三个子任务,差分统计即可。
考虑 m = 0 m=0 m=0,即没有障碍物的情况,对应 Subtask 4。
记 f i , j f_{i,j} fi,j 表示从第一列到第 i i i 列,第 j j j 行的方案数。
那么, f i , j = f i − 1 , j − 1 + f i − 1 , j + f i − 1 , j + 1 f_{i,j}=f_{i-1,j-1}+f_{i-1,j}+f_{i-1,j+1} fi,j=fi−1,j−1+fi−1,j+fi−1,j+1。
注意到 j ≤ 6 j \le 6 j≤6,考虑采用矩阵形式,记 F i = [ f i , 1 f i , 2 . . . f i , 6 ] F_i=\begin{bmatrix} f_{i,1} & f_{i,2} &...& f_{i,6} \end{bmatrix} Fi=[fi,1fi,2...fi,6],有:
F i = F i − 1 [ 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1 ] F_i =F_{i-1} \begin{bmatrix} 1 & 1 & 0 & 0 & 0 & 0\\ 1 & 1 & 1 & 0 & 0 & 0\\ 0 & 1 & 1 & 1 & 0 & 0\\ 0 & 0 & 1 & 1 & 1 & 0\\ 0 & 0 & 0 & 1 & 1 & 1\\ 0 & 0 & 0 & 0 & 1 & 1\\ \end{bmatrix} Fi=Fi−1 110000111000011100001110000111000011 。
得 F n = F 1 × [ . . . ] n − 1 F_n=F_1\times \begin{bmatrix} ... \end{bmatrix}^{n-1} Fn=F1×[...]n−1,初始状态 F 1 = [ 1 1 . . . 1 ] F_1=\begin{bmatrix} 1 & 1 &...& 1 \end{bmatrix} F1=[11...1] 。
矩阵快速幂即可,时间复杂度 ( 6 3 log n ) (6^3 \log n) (63logn)。
#include
#define int long long
using namespace std;
const int mod = 1e9 + 7;
struct Matrix{
int a[7][7];
Matrix(){
memset(a, 0, sizeof(a));
}
};
Matrix A, F;
Matrix operator * (Matrix x, Matrix y)
{
Matrix res;
for(int i=1; i<=6; i++)
for(int j=1; j<=6; j++)
for(int k=1; k<=6; k++)
res.a[i][j] = (res.a[i][j] + x.a[i][k] * y.a[k][j]) % mod;
return res;
}
Matrix qpow(Matrix B, int b)
{
b--;
Matrix res = B, base = B;
while(b)
{
if(b & 1) res = res * base;
b >>= 1;
base = base * base;
}
return res;
}
int n, m;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
// 初始值
for(int i=1; i<=6; i++) A.a[i][i-1] = A.a[i][i] = A.a[i][i+1] = 1;
for(int i=1; i<=6; i++) F.a[1][i] = 1;
F = F * qpow(A, n-1);
cout << (F.a[1][1] + F.a[1][2] + F.a[1][3] + F.a[1][4] + F.a[1][5] + F.a[1][6]) % mod;;
return 0;
}
不同的障碍物状态对应不同的转移矩阵:
举个例子,如果第 i i i 列,第 3 , 4 3,4 3,4 行有障碍物,那么 f i , 3 , f i , 4 = 0 f_{i,3},f_{i,4}=0 fi,3,fi,4=0,对应的矩阵的第 3 , 4 3,4 3,4 列为 0 0 0:
F i = F i − 1 [ 1 1 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 1 1 ] F_i =F_{i-1} \begin{bmatrix} 1 & 1 & 0 & 0 & 0 & 0\\ 1 & 1 & 0 & 0 & 0 & 0\\ 0 & 1 & 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0 & 1 & 0\\ 0 & 0 & 0 & 0 & 1 & 1\\ 0 & 0 & 0 & 0 & 1 & 1\\ \end{bmatrix} Fi=Fi−1 110000111000000000000000000111000011 。
而第 l l l 到第 r r r 列若每列障碍物状态均相同,则转移矩阵均相同为 B B B ,有 F r = F r − 1 × B = F r − 2 × B 2 = . . . = F l − 1 × B r − l + 1 F_r = F_{r-1} \times B=F_{r-2} \times B^2=...=F_{l-1}\times B ^ {r-l+1} Fr=Fr−1×B=Fr−2×B2=...=Fl−1×Br−l+1。
考虑将 1 1 1 到 n n n 划分成若干段转移矩阵相同的连续区间。注意到这样的区间至多 2 m 2m 2m 个,可以顺序枚举区间,在更新 [ l , r ] [l,r] [l,r] 答案之前即表示 F l − 1 F_{l-1} Fl−1。同时每次 O ( m ) O(m) O(m) 枚举障碍物得到 [ l , r ] [l,r] [l,r] 间的转移矩阵 B B B。
void modify(int l, int r)
{
if(l > r) return ;
// 统计会影响 [l,r] 的障碍物并修改状态。
Matrix B = A;
for(int j=1; j<=m; j++)
{
// 分段后的区间一定被一些障碍物完全覆盖,若不完全,则 [l,r] 中一定存在两种状态。
if(a[j].y1 <= l and r <= a[j].y2)
{
for(int k=a[j].x1; k<=a[j].x2; k++)
B.a[1][k] = B.a[2][k] = B.a[3][k] = B.a[4][k] = B.a[5][k] = B.a[6][k] = 0;
}
}
F = F * qpow(B, r-l+1);
}
对于具体分段,我们考虑按照所有障碍物左右边界为断点分割:
for(int i=1; i<=m; i++)
cin >> a[i].x1 >> a[i].y1 >> a[i].x2 >> a[i].y2,
pos[++tot] = a[i].y1, pos[++tot] = a[i].y2;
sort(pos+1, pos+tot+1);
tot = unique(pos+1, pos+tot+1) - pos - 1;
对于每个断点单独讨论,将 [ p o s 1 , p o s t o t ) [pos_1,pos_{tot}) [pos1,postot) 划分为: [ p o s 1 , p o s 1 ] [pos_1,pos_1] [pos1,pos1]、 ( p o s 1 , p o s 2 ) (pos_1,pos_{2}) (pos1,pos2)、 [ p o s 2 , p o s 2 ] [pos_{2},pos_{2}] [pos2,pos2]、 . . . ... ... 、 ( p o s t o t − 1 , p o s t o t ) (pos_{tot-1},pos_{tot}) (postot−1,postot)。
总时间复杂度 O ( m × ( m + 6 3 log n ) ) O(m \times ( m + 6^3 \log n)) O(m×(m+63logn))。
#include
#define int long long
using namespace std;
const int mod = 1e9 + 7;
struct Matrix{ int a[7][7]; Matrix(){ memset(a, 0, sizeof(a)); } };
Matrix A, F;
Matrix operator * (Matrix x, Matrix y){ Matrix res; for(int i=1; i<=6; i++) for(int j=1; j<=6; j++) for(int k=1; k<=6; k++) res.a[i][j] = (res.a[i][j] + x.a[i][k] * y.a[k][j]) % mod; return res;}
Matrix qpow(Matrix B, int b) { b--; Matrix res = B, base = B; while(b) { if(b & 1) res = res * base;b >>= 1; base = base * base; } return res;}
int n, m, tot, pos[2005];
struct Node{ int x1, y1, x2, y2; }a[1005];
void modify(int l, int r)
{
Matrix B = A;
if(l > r) return ;
for(int j=1; j<=m; j++)
{
if(a[j].y1 <= l and r <= a[j].y2)
{
for(int k=a[j].x1; k<=a[j].x2; k++)
B.a[1][k] = B.a[2][k] = B.a[3][k] = B.a[4][k] = B.a[5][k] = B.a[6][k] = 0;
}
}
F = F * qpow(B, r-l+1);
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
//初始值
for(int i=1; i<=6; i++) A.a[i][i-1] = A.a[i][i] = A.a[i][i+1] = 1;
for(int i=1; i<=6; i++) F.a[1][i] = 1;
for(int i=1; i<=m; i++)
cin >> a[i].x1 >> a[i].y1 >> a[i].x2 >> a[i].y2,
pos[++tot] = a[i].y1, pos[++tot] = a[i].y2;
pos[++tot] = 2, pos[++tot] = n+1;
sort(pos+1, pos+tot+1); tot = unique(pos+1, pos+tot+1) - pos - 1;
for(int i=1; i<tot; i++)
{
modify(pos[i], pos[i]);
modify(pos[i]+1, pos[i+1]-1);
}
cout << (F.a[1][1] + F.a[1][2] + F.a[1][3] + F.a[1][4] + F.a[1][5] + F.a[1][6]) % mod;
return 0;
}