HDU 5745 La Vie en rose(DP+bitset优化)
[題目鏈接]
[題意]
給定模式串和主串,模式串可以交換相鄰位子的字符,且可以交換多個位子,但每個字符只能被交換一次。問模式串能否通過該變換與主串匹配?輸出主串中每個位子的匹配結果,1為可匹配,0為不可匹配。
[分析]
賽上被這道題坑哭了,看到那么多隊過自己卻沒有思路,好不容易想到個方法把樣例過了卻T了。最后走投無路寫了個暴力就A了,1500ms,嚇死。
不過賽后貌似加強了數據,卡了暴力,喪病。
不過趁機學習了下bitset優化的方法,還不錯
dp公式很容易得到
設主串為s,模式串為t,dp[i][j][k]表示主串到i,模式串到j,模式串當前位置的狀態為k(0:不動,1:與前面交換,2:與后面交換)是否匹配,則:
dp[i][j][0] = (dp[i-1][j-1][0] || dp[i-1][j-1][1] ) && (s[i] == t[j])
dp[i][j][1] = (dp[i-1][j-1][2] ) && ( s[i-1] == t[j] )
dp[i][j][2] = (dp[i-1][j-1][0] || dp[i-1][j-1][1] )&& (s[i+1] == t[j] )
優化1:
第二維j實際上只與j-1有關,可以滾動
優化2:
所有值都是bool類型,可以用bitset壓位,通過bitset之間的位運算,常數優化
其實聽了這些對不會玩bitset的來說還是一臉懵逼(比如我
所以具體一點吧
首先需要這些bitset,前者當然是存dp值,2用于滾動,3存三種狀態;后者對應26個字母是否在主串中的某個位子出現,比如ch[0][5]表示字母a是否出現在主串中的第5個位子
dp[cur][1] = (dp[cur^1][2] << 1) & ch[t[i-1]-'a'] ;轉移的時候這樣搞,這里只列出了k=1的轉移寫法
由于兩個bitset可以直接進行位運算,相當于一次運算直接把1-n的所有dp值全部算出,復雜度卻只有O(n/w)(w是機器的字節長)
所以預處理每個字符是否在每個位子出現,保存在bitset中,就是為了這里的操作
還有一個疑問,為何要<<1?
很簡單,因為i由i-1推得,所以左移1使得對應的位對齊,再運算
這樣寫剛好卡過
[代碼]
#include <bits/stdc++.h> using namespace std ; const int N = 100000 + 5 ; typedef long long LL ;int T , n , m ; char s[N] , t[N] ; bitset<N> dp[2][3] , ch[26] ;int main() {scanf( "%d" , &T ) ;while( T-- ){scanf( "%d%d" , &n , &m ) ;scanf( "%s%s" , s+1 , t+1 ) ;for( int i = 0 ; i < 26 ; i++ )ch[i].reset() ;for( int i = 1 ; i <= n ; i++ )ch[s[i]-'a'].set(i) ;int cur = 0 ;dp[cur][0].set() ;dp[cur][1].reset() ;dp[cur][2].reset() ;for( int i = 1 ; i <= m ; i++ ){cur ^= 1 ;for( int j = 0 ; j < 3 ; j++ )dp[cur][j].reset() ;dp[cur][0] = ((dp[cur^1][0] | dp[cur^1][1]) << 1) & ch[t[i]-'a'] ;if( i > 1 )dp[cur][1] = (dp[cur^1][2] << 1) & ch[t[i-1]-'a'] ;if( i < m )dp[cur][2] = ((dp[cur^1][1] | dp[cur^1][0]) << 1) & ch[t[i+1]-'a'] ;}for( int i = m ; i <= n ; i++ )s[i-m] = '0' + (dp[cur][0][i] | dp[cur][1][i]) ;for( int i = n-m+1 ; i < n ; i++ )s[i] = '0' ;s[n] = 0 ;puts(s) ;}return 0 ; }總結
以上是生活随笔為你收集整理的HDU 5745 La Vie en rose(DP+bitset优化)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android android_id,
- 下一篇: springboot——数据层访问搭建