Solution -「NOI 2021」「洛谷 P7740」機器人遊戲
阿新 • • 發佈:2021-08-08
\(\mathcal{Description}\)
Link.
自己去讀題面叭~
\(\mathcal{Solution}\)
首先,參悟【樣例解釋 #2】。一種暴力的思路即為欽定集合 \(S\) 內的位置都合法,容斥計數。其中對於每條紙帶的每個位置,有三種情況(令 _
為“保持不變”,注意沒有被機器人經過的位置都有這種修改):
- 同時存在
_
和*
;或者同時存在0
和1
:只能為空,方案數為 \(1\); - 否則,存在(
_
或*
)且存在(0
或1
):只能為空或01
中的一個,方案數為 \(2\); - 否則,方案數為 \(3\)。
暴力做的複雜度是 \(\mathcal O(2^nn^am^b)\)
嘗試欽定最後一個在 \(S\) 中的位置為 \(r\),那麼所有修改長度大於 \(n-r+1\) 的機器人所在的紙帶都必須全空。在此限制下帶著容斥係數狀壓 DP,令 \(f(i,S)\) 表示考慮了紙帶的位置 \(i\),前若干個位置的選擇情況為 \(S\),注意此處 \(|S|\le2^{\min\{i,n-r\}}=\mathcal O(2^{n/2})\),轉移時可以 \(\mathcal O(nm)\) 暴力計算當前位置的貢獻,得到了 \(\mathcal O(2^{n/2}nm)\) 的演算法。
順帶,注意到統計當前位置貢獻時可以描述為形如“有多少個機器人的修改序列中,下標屬於 \(S\)
_
/*
/0
/1
”,可以用 std::bitset
優化。最終複雜度為 \(\mathcal O(\frac{2^{n/2}nm}{\omega})\)。
\(\mathcal{Code}\)
/*~Rainybunny~*/ #include <bitset> #include <cstdio> #include <cassert> #include <cstring> #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i ) #define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i ) typedef unsigned long long ULL; const int MAXN = 32, MAXM = 1e3, MOD = 1e9 + 7; int n, m, pw2[MAXM + 5], pw3[MAXM + 5]; inline int imin( const int a, const int b ) { return a < b ? a : b; } inline void subeq( int& a, const int b ) { ( a -= b ) < 0 && ( a += MOD ); } inline int mul( const int a, const int b ) { return int( 1ll * a * b % MOD ); } inline int add( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; } inline void addeq( int& a, const int b ) { ( a += b ) >= MOD && ( a -= MOD ); } struct Robot { int len, val[MAXN + 5]; inline int operator [] ( const int k ) const { return k <= len ? val[k] : 0; } inline void read() { static char str[105]; scanf( "%s", str ); val[len = 1] = 0; for ( int i = 0; str[i]; ++i ) { if ( str[i] == 'R' ) val[++len] = 0; else if ( str[i] == '0' ) val[len] = 1; else if ( str[i] == '1' ) val[len] = 2; else val[len] = 3 - val[len]; } } } rbt[MAXM + 5]; inline int solve( const int r ) { static int f[2][1 << 17][2]; static std::bitset<MAXM + 5> sig[MAXN + 5][4], g[1 << 17][4]; int allc = 0; rep ( i, 0, n - 1 ) rep ( j, 0, 3 ) sig[i][j].reset(); rep ( i, 1, m ) if ( rbt[i].len <= n - r + 1 ) { ++allc; rep ( j, 0, n - 1 ) sig[j][rbt[i][j + 1]].set( i ); } rep ( i, 0, imin( n - r, r ) ) rep ( j, 0, 3 ) { g[1 << i][j] = sig[i][j]; } rep ( S, 1, ( 1 << imin( n - r, r ) << 1 ) - 1 ) if ( S & ( S - 1 ) ) { rep ( i, 0, 3 ) { g[S][i] = g[S ^ ( S & -S )][i] | g[S & -S][i]; } } auto calc = [&]( const bool sty, const ULL S )->int { static std::bitset<MAXM + 5> x, y; x = ( sty ? g[S][3] : g[S][0] & g[S][3] ) | ( g[S][1] & g[S][2] ); y = ~x & ( sty ? g[S][1] | g[S][2] : ( g[S][0] | g[S][3] ) & ( g[S][1] | g[S][2] ) ); int t = y.count(); return mul( pw2[t], pw3[allc - t - x.count()] ); }; memset( f[0], 0, sizeof f[0] ), f[0][0][0] = 1; for ( int i = 0, sta = 0; i < r; ++i, sta ^= 1 ) { memset( f[!sta], 0, sizeof f[!sta] ); rep ( S, 0, ( 1 << imin( i, n - r ) ) - 1 ) { ULL T = ULL( S ) << 1ull & ( ( 1ull << n >> r ) - 1 ); bool flg = ULL( S ) << 1ull << r >> n & 1ull; rep ( t, 0, 1 ) { int cur = f[sta][S][t]; f[sta][S][t] = 0; if ( !cur ) continue; subeq( f[!sta][r == n ? 0 : T | 1][t || flg || r == n], mul( cur, calc( t || i + 1 < r, S << 1 | 1 ) ) ); if ( i + 1 < r ) { addeq( f[!sta][T][t || flg], mul( cur, calc( 1, S << 1 ) ) ); } } } } int ret = 0; rep ( t, 0, 1 ) { for ( int d = 1, sta = r & 1; d <= n - r; ++d, sta ^= 1 ) { rep ( i, 0, imin( r, n - r ) - 1 ) { rep ( j, t, 3 ) g[1 << i][j] = sig[i + d][j]; } rep ( S, 0, ( 1 << imin( r, n - r ) ) - 1 ) { if ( S & ( S - 1 ) ) { rep ( j, t, 3 ) { g[S][j] = g[S ^ ( S & -S )][j] | g[S & -S][j]; } } f[!sta][S][t] = mul( f[sta][S][t], calc( t, S ) ); f[sta][S][t] = 0; } } rep ( S, 0, ( 1 << imin( r, n - r ) ) - 1 ) { addeq( ret, f[n & 1][S][t] ); } } return ret; } int main() { // freopen( "robot.in", "r", stdin ); // freopen( "robot.out", "w", stdout ); scanf( "%d %d", &n, &m ); pw2[0] = pw3[0] = 1; rep ( i, 1, m ) { rbt[i].read(); pw2[i] = mul( 2, pw2[i - 1] ), pw3[i] = mul( 3, pw3[i - 1] ); } int ans = 0; rep ( i, 1, n ) subeq( ans, solve( i ) ); printf( "%d\n", ans ); return 0; }