T2 波特 题解

contest link

T2 波特

题目

P0

n ≤ 1 0 5 n \le 10^5 n105 对应前三个子任务,差分统计即可。

P1 无障碍物

考虑 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=fi1,j1+fi1,j+fi1,j+1

注意到 j ≤ 6 j \le 6 j6,考虑采用矩阵形式,记 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=Fi1 110000111000011100001110000111000011

F n = F 1 × [ . . . ] n − 1 F_n=F_1\times \begin{bmatrix} ... \end{bmatrix}^{n-1} Fn=F1×[...]n1,初始状态 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;
}

P2 有障碍物

  • 不同的障碍物状态对应不同的转移矩阵:

    举个例子,如果第 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=Fi1 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=Fr1×B=Fr2×B2=...=Fl1×Brl+1

    考虑将 1 1 1 n n n 划分成若干段转移矩阵相同的连续区间。注意到这样的区间至多 2 m 2m 2m 个,可以顺序枚举区间,在更新 [ l , r ] [l,r] [l,r] 答案之前即表示 F l − 1 F_{l-1} Fl1。同时每次 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}) (postot1,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;
}

你可能感兴趣的:(题解,c++)