CF1392G-Omkar and Pies【dp】
阿新 • • 發佈:2021-06-16
正題
題目連結:https://www.luogu.com.cn/problem/CF1392G
題目大意
兩個長度為\(k\)的起始和目標01串。
\(n\)個操作交換起始串的兩個位置,選擇一段長度至少為\(m\)的連續操作序列使得相同的位數最多。
\(1\leq m\leq n\leq 10^6,1\leq k\leq 20\)
解題思路
因為是從前往後操作,所以可以拆成兩個字尾\([l,n]\)和\([r+1,n]\)。
對\(S\)執行\(l\sim n\)然後對\(T\)執行\(r+1\sim n\)之後比較就好了。
額考慮怎麼做這個東西,我們可以\(O(nk)\)的處理出一個\(s_i\)表示對\(S\)
然後我們要找到一對\(l,r\)使得\(r-l\geq m\)且\(s_l\ xor\ t_r\)的\(1\)最多。
有個做法是考慮\(s\ and\ t\)的\(1\)數,因為\(s\)和\(t\)的\(1\)數固定。設\(s\ and\ t\)有\(z\)個\(1\),\(s\)有\(x\)個\(1\),\(t\)有\(y\)個\(1\),那麼他們相同的位數有\(z+(k-x-y+z)=2z+k-x-y\)個,所以其實是要最大化\(z\)就好了。
設\(f_{i}\)
然後求出這兩個就可以搞定這題了,因為是最值所以不需要用到\(\text{FWT}\),直接\(dp\)就好了。
時間複雜度\(O(nk)\)
code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1<<20; int k,n,m,s,t,zx[N],zy[N],f[N],g[N],bit[N],rev[N][20]; char st[30]; int swp(int s,int p){ int ans=0; for(int i=0;i<k;i++) ans|=(((s>>rev[p][i])&1)<<i); return ans; } int main() { scanf("%d%d%d",&n,&m,&k); scanf("%s",st); for(int i=0;i<k;i++) s|=(st[i]-'0')*(1<<i); scanf("%s",st); for(int i=0;i<k;i++) t|=(st[i]-'0')*(1<<i); for(int i=1;i<=n;i++){ int x,y; scanf("%d%d",&x,&y);x--;y--; for(int j=0;j<k;j++)rev[i][j]=j; swap(rev[i][x],rev[i][y]); } for(int i=n-1;i>=1;i--){ int tmp[k]; for(int j=0;j<k;j++) tmp[j]=rev[i][rev[i+1][j]]; for(int j=0;j<k;j++)rev[i][j]=tmp[j]; } memset(f,0x3f,sizeof(f)); for(int i=n;i>=1;i--){ int x=swp(s,i);f[x]=min(f[x],i); x=swp(t,i); g[x]=max(g[x],i); } g[t]=n+1;int MS=(1<<k); for(int i=1;i<MS;i++) bit[i]=bit[i-(i&-i)]+1; int ans=-1,ansl=0,ansr=0; for(int i=MS-1;i>=0;i--){ for(int j=0;j<k;j++){ f[i]=min(f[i],f[i|(1<<j)]); g[i]=max(g[i],g[i|(1<<j)]); } if(bit[i]>ans&&g[i]-f[i]>=m) ans=bit[i],ansl=f[i],ansr=g[i]; } printf("%d\n%d %d\n",2*ans+k-bit[s]-bit[t],ansl,ansr-1); return 0; }