1. 程式人生 > 實用技巧 >Solution -「AGC 013E」「AT 2371」Placing Squares

Solution -「AGC 013E」「AT 2371」Placing Squares

\(\mathcal{Description}\)

  Link.

  給定一個長度為 \(n\) 的木板,木板上有 \(m\) 個標記點,第 \(i\) 個標記點距離木板左端點的距離為 \(x_i\),現在你需要在木板上放置一些不相交正方形,正方形需要滿足:

  • 正方形的邊長為整數。

  • 正方形底面需要緊貼木板。

  • 正方形不能超出木板,正方形要將所有的木板覆蓋。

  • 標記點的位置不能是兩個正方形的交界處。

  求所有合法放置方案的正方形面積的乘積之和。對 \(10^9+7\) 取模。

  \(n\le10^9\)\(m\le10^5\)

\(\mathcal{Solution}\)

  嘛……有時候題意轉換……就挺突然的 qwq。

你有 \(n\) 個空格排成一行,格子邊緣可以放隔板,其中第一格左側和最後一格右側必須放,標記位置不能放。然後在每兩塊隔板間放兩個不同色的小球,可以放同一個位置。求方案數。

  不難證明與原問題等價。我們來考慮這個新問題。

  令 \(f(i,0/1/2)\) 表示前 \(i\) 個位置放好球,其中最後一段區間已經放了 \(0/1/2\) 個球的方案數。轉移:

  • 不放隔板:

\[\begin{aligned} f(i,0)&=f(i-1,0)\\ f(i,1)&=f(i-1,1)+f(i-1,0)\\ f(i,2)&=f(i-1,2)+2f(i-1,1)+f(i-1,0) \end{aligned} \]

  • 放隔板:

\[f(i,0/1/2)=f(i-1,2) \]

  實際上只需要“隨便放”和“不放”兩種選擇,把狀態寫成列向量 \(\begin{bmatrix}f(i,0)\\f(i,1)\\f(i,2)\end{bmatrix}\),構造兩種轉移矩陣:

  • 不放:

\[A=\begin{bmatrix} 1&0&0\\ 2&1&0\\ 1&1&1 \end{bmatrix} \]

  • 隨便放:

\[B=\begin{bmatrix} 2&1&1\\ 2&1&0\\ 1&1&1 \end{bmatrix} \]

  在相鄰兩個標記點之間矩陣快速冪加速 DP 即可。複雜度 \(\mathcal O(3^3m\log n)\)

\(\mathcal{Code}\)

#include <cstdio>
#include <assert.h>

typedef long long LL;

const int MAXM = 1e5, MOD = 1e9 + 7;
int n, m;

inline int add ( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
inline int mul ( LL a, const int b ) { return ( a *= b ) < MOD ? a : a % MOD; }

inline int rint () {
	int x = 0; char s = getchar ();
	for ( ; s < '0' || '9' < s; s = getchar () );
	for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
	return x;
}

struct Matrix {
	int n, m, mat[3][3];
	Matrix (): n ( 0 ), m ( 0 ), mat {} {}
	Matrix ( const int tn, const int tm ): n ( tn ), m ( tm ), mat {} {}
	inline int* operator [] ( const int key ) { return mat[key]; }
	inline Matrix operator * ( Matrix t ) {
		assert ( m == t.n );
		Matrix ret ( n, t.m );
		for ( int i = 0; i < n; ++ i ) {
			for ( int k = 0; k < m; ++ k ) {
				for ( int j = 0; j < t.m; ++ j ) {
					ret[i][j] = add ( ret[i][j], mul ( mat[i][k], t[k][j] ) );
				}
			}
		}
		return ret;
	}
};

inline Matrix qkpow ( Matrix a, int b ) {
	Matrix ret ( a.n, a.m );
	for ( int i = 0; i < ret.n; ++ i ) ret[i][i] = 1;
	for ( ; b; a = a * a, b >>= 1 ) if ( b & 1 ) ret = ret * a;
	return ret;
}

Matrix I ( 3, 1 ), A ( 3, 3 ), B ( 3, 3 );

inline void init () {
	I[0][0] = 1;
	A[0][0] = 1;
	A[1][0] = 2, A[1][1] = 1;
	A[2][0] = A[2][1] = A[2][2] = 1;
	B = A, ++ B[0][0], ++ B[0][1], ++ B[0][2];
}

int main () {
	init ();
	n = rint (), m = rint ();
	int las = 0;
	for ( int i = 1, x; i <= m; ++ i ) {
		x = rint ();
		I = A * qkpow ( B, x - las - 1 ) * I;
		las = x;
	}
	
	I = A * qkpow ( B, n - las - 1 ) * I;
	printf ( "%d\n", I[2][0] );
	return 0;
}