[Codeforces 1221D]Make The Fence Great Again-dp

說在前面

一如既往的菜
只能切水題


題目

codeforces 1227D傳送門


解法

對於某個和旁邊相同高度的柵欄,我們不需要讓它增加很高,只需要讓它和旁邊的柵欄高度不同就行了
顯然一個柵欄的高度增加不會超過2,狀壓就行了

證明:如果最優方案中,有一個柵欄的高度增加了3,那麼必然存在0,1,2中的某個值,將它的高度增加值換成該值後,仍然不與相鄰柵欄衝突(因爲相鄰柵欄高度只有兩種,而 Δ=0,1,2\Delta=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() ;
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章