說在前面
一如既往的菜
只能切水題
題目
解法
對於某個和旁邊相同高度的柵欄,我們不需要讓它增加很高,只需要讓它和旁邊的柵欄高度不同就行了
顯然一個柵欄的高度增加不會超過2,狀壓就行了
證明:如果最優方案中,有一個柵欄的高度增加了3,那麼必然存在0,1,2中的某個值,將它的高度增加值換成該值後,仍然不與相鄰柵欄衝突(因爲相鄰柵欄高度只有兩種,而 有三種高度)。所以原來的方案不是最優的,證畢
下面是代碼
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int Q , N , a[300005] , b[300005] ;
long long f[2][27] ;
/*
0 000
1 001
2 010
3 011
4 100
5 101
6 110
7 111
*/
template <typename T>
void smin( T &A , T B ){
if( A > B ) A = B ;
}
bool state_check( int pos , int s ){
if( pos == 1 ) return true ;
int s1 = s % 3 , s2 = ( s / 3 ) % 3 , s3 = ( s / 9 ) % 3 ;
if( a[pos] + s1 != a[pos-1] + s2 && a[pos-2] + s3 != a[pos-1] + s2 ) return true ;
return false ;
}
bool trans_check( int t , int s ){
int t1 = t % 3 , t2 = ( t / 3 ) % 3 ;
int s2 = ( s / 3 ) % 3 , s3 = ( s / 9 ) % 3 ;
if( t1 != s2 || t2 != s3 ) return false ;
return true ;
}
void solve(){
memset( f , 0 , sizeof( f ) ) ;
int pre = 0 , now = 1 ;
for( int i = 1 ; i <= N ; i ++ ){
swap( now , pre ) ;
for( int j = 0 ; j <= 26 ; j ++ ){
f[now][j] = 1e18 ;
if( state_check( i , j ) == false ) continue ;
int delta = ( j % 3 ) * b[i] ;
for( int k = 0 ; k <= 26 ; k ++ ){
if( trans_check( k , j ) ) smin( f[now][j] , f[pre][k] + delta ) ;
}
}
}
long long ans = 1e18 ;
for( int i = 0 ; i <= 26 ; i ++ )
smin( ans , f[now][i] ) ;
printf( "%lld\n" , ans ) ;
}
int main(){
scanf( "%d" , &Q ) ;
while( Q -- ){
scanf( "%d" , &N ) ;
for( int i = 1 ; i <= N ; i ++ )
scanf( "%d%d" , &a[i] , &b[i] ) ;
a[0] = -1 ;
solve() ;
}
}