[2021-09-09 T3] 序列/luogu P3943 星空(异或差分+bfs最短路+状压dp)
序列
- description
- solution
- code
description
題目描述
長度為nnn的序列,初始全為000,每次可以選擇?個數ai(1≤i≤l)a_i(1\le i\le l)ai?(1≤i≤l),然后選擇連續aia_iai?個元素異或上111
求最少的次數,使得對于所有i(1≤i≤k)i(1\le i\le k)i(1≤i≤k)滿足第iii個位置是111,其他的位置都是000
輸入格式
第?行三個數n,m,kn,m,kn,m,k
第二行kkk個數分別表示x1,x2,...,xkx_1,x_2,...,x_kx1?,x2?,...,xk?
第三行lll個數分別表示a1,a2,...ala_1,a_2,...a_la1?,a2?,...al?
輸出格式
一個數表示答案,若不能達到輸出-1
樣例
10 2 3 1 2 6 10 4 2數據范圍
n≤10000,k≤10,l≤100n\le 10000,k\le 10,l\le 100n≤10000,k≤10,l≤100
solution
異或常見有兩種處理
-
0-1異或類,權值只有0,1
顯然某位異或偶數次相當于沒操作,這就可以轉化成差分
-
普通異或類
按二進制拆位做,每位答案是獨立的
此題就是差分做法
e.g. 目標結果:1 0 0 1 1 0,相鄰兩位權值不同就要差分出來
操作一段長為aia_iai?的段,就相當于在pos,pos+aipos,pos+a_ipos,pos+ai?兩個位置異或111
本題kkk范圍極小,差分出來最多也就202020個位置
考慮從最后的狀態用最少操作數變成全000的初始狀態
這相當于一張n+1n+1n+1點姻緣圖,在差分2k2k2k個位置上有人,位置相差為aia_iai?的點對間有無向邊,人沿著邊移動,兩人相遇牽手成功離開,求最少走過的邊數,使得每個人都能找到自己的心動嘉賓
用bfs處理出,每個人到達所有點走過的最少邊數,到不了就置為inf
總人數不多,可以狀壓dp枚舉每次是哪兩個人牽手成功,轉移即可
code
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define inf 0x3f3f3f3f queue < pair < int, int > > q; int n, k, l, cnt; int dis[22][100002]; int x[100002], a[105], c[25]; int dp[1 << 22];int dfs( int s ) {if( ! s ) return 0;if( dp[s] ^ inf ) return dp[s];int &ans = dp[s], x = __builtin_ctz( s );for( int y = cnt - 1;y > x;y -- )if( 1 << y & s ) {int t = dfs( s ^ ( 1 << y ) ^ ( 1 << x ) );ans = min( ans, t + dis[x][c[y]] );}return ans; }int main() {scanf( "%d %d %d", &n, &k, &l );for( int i = 1, pos;i <= k;i ++ ) {scanf( "%d", &pos );x[-- pos] = 1;}for( int i = 1;i <= l;i ++ )scanf( "%d", &a[i] );if( x[0] ) c[cnt ++] = 0;for( int i = 1;i <= n;i ++ )if( x[i] ^ x[i - 1] ) c[cnt ++] = i;if( cnt & 1 ) return ! printf( "-1" );memset( dp, 0x3f, sizeof( dp ) );memset( dis, 0x3f, sizeof( dis ) );for( int i = 0, j, d, pos;i < cnt;i ++ ) {dis[i][c[i]] = 0;q.push( make_pair( 0, c[i] ) );while( ! q.empty() ) {d = q.front().first, pos = q.front().second; q.pop();for( k = 1;k <= l;k ++ ) {j = pos + a[k];if( j <= n and dis[i][j] == inf )dis[i][j] = d + 1, q.push( make_pair( d + 1, j ) );j = pos - a[k];if( j >= 0 and dis[i][j] == inf )dis[i][j] = d + 1, q.push( make_pair( d + 1, j ) );}}}int ans = dfs( ( 1 << cnt ) - 1 );printf( "%d\n", ans == inf ? -1 : ans );return 0; }總結
以上是生活随笔為你收集整理的[2021-09-09 T3] 序列/luogu P3943 星空(异或差分+bfs最短路+状压dp)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iTunes store里显示电影商店不
- 下一篇: [NOI2018] 归程(线段树维护并查