20210524考试—奇怪的道路 题解
考场上不知道为什么,我一直想打暴力然后打个表,因为数据范围可以打表,根本想都没有想正解这回事,也许是对自己的不自信吧。(自信也没用)
考场上选择性眼瞎,没看到\(k<=8\),所以当他们说是状压的时候我都很惊讶。但是我也否定了组合数做法。
这个方程很好推,就是状态不好设计。
首先把\(i,j\)设为处理好的点数,边数这个不难想到。
这里一个小细节,状态设计一定要严谨,否则越推越乱,\(i\)表示已经处理好\(i-1\)个点,正在处理第\(i\)个点。
有一点我感觉我在这有思维误区,其实很多题我都栽到这个点上面,很重要。
当题目描述的东西有后效性的时候,与其想如何处理这个后效性,更多的应该想能不能不鸟这个后效性。
我觉得基站选址也是这个意思,其实重点就是这个,你会发现如果你管后面的\(k\)个点,你也管不过来,因为当前点并不能决定后面的点。
所以第三维就被设计出来\([i-k,k]\)这个区间内的连边状态,如果奇数为\(1\),偶数为\(0\)。
即使你设计出来这三维,发现转移的式子还是推不出来。因为你根本不知道你处理的点再跟谁连边。
我们自然会想一重循环枚举在和谁连边。即使枚举,发现由于无法记录,我们不知道当前状态要转移到哪里。
所以设计出来第四维:正在处理\(i\)和\(i-k+l\)的连边。
其实这个状态设计出来,题基本就完事了。
还要注意一个点,我们要把自己连边的奇偶性也压进去,这样方便我们进行转移。
如果\(i\)和\(i-k+l\)连边
\(f[i][j+1][k \ xor \ (1<<K) \ xor \ (1 << l ) ][l]+=f[i][j][k][l]\)
这是因为连边之后当前点和被连点的奇偶性都要改变
如果不连
\(f[i][j][k][l+1] += f [i][j][k][l]\)
如果已经处理完当前点的所有连边,准备向下一个点转移
\(f[i+1][j][k>>1][max(0,K-i)]+=f[i][j][k][l]\)
这里有两个需要注意:
1.只有当最后一位的连边是偶数才能转移。
2.\(max(0,K-i)\)保证了我们转移到一个合法状态上。
code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <bitset>
#define int long
#define R register int
#define printf Ruusupuu = printf
using namespace std ;
typedef long long L ;
typedef long double D ;
const int M = 1e9 + 7 ;
const int N = 3e1 + 10 ;
const int K = 10 ;
inline int read(){
int w = 0 ; bool fg = 0 ; char ch = getchar() ;
while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - '0' ) , ch = getchar() ;
return fg ? -w : w ;
}
inline void A( int & a , int b ){ a = a + b > M ? a + b - M : a + b ; }
inline int AA( int a , int b ){ return a + b > M ? a + b - M : a + b ; }
inline void debug( int x ){ cout << bitset<10> ( x ) << endl ; }
inline int maxs( int a , int b ){ return a > b ? a : b ; }
int Ruusupuu , n , m , kk ;
int f [N][N][1 << K][K] ;
//已经处理好i-1个点,正在处理第i个点;已经连接j条路;[i-kk+l,i]的状态为k(偶数为0,奇数为1),正在处理i-kk+l时候的方案
void sc(){
n = read() , m = read() , kk = read() ;
}
void work(){
f [1][0][0][kk] = 1 ;
for( R i = 1 ; i <= n ; i ++ ){
for( R j = 0 ; j <= m ; j ++ ){
for( R k = 0 ; k < ( 1 << ( kk + 1 ) ) ; k ++ ){
for( R l = 0 ; l <= kk ; l ++ ){
if( i - kk + l < 1 ) continue ;
// debug( k ) , printf( "%ld %ld %ld %ld\n" , i , j , l , f [i][j][k][l] ) ;
if( l == kk && !( k & 1 ) ) A( f [i + 1][j][k >> 1][maxs( 0l , - i + kk )] , f [i][j][k][l] ) ;
else if( l != kk ){
A ( f [i][j + 1][k ^ ( 1 << kk ) ^ ( 1 << l )][l] , f [i][j][k][l] ) ;
A ( f [i][j][k][l + 1] , f [i][j][k][l] ) ;
}
}
}
}
}
printf( "%ld\n" , f [n][m][0][kk] ) ;
}
signed main(){
sc() ;
work() ;
return 0 ;
}

浙公网安备 33010602011771号