A. 二进制(binary)
给定 \(01\) 串 \(S, T\),你可以进行如下操作若干次:选定 \(S\) 中相邻两个字符并交换。
你需要最大化操作结束后,\(T\) 在 \(S\) 中的「出现次数」,同时你还需要回答,在达到这个最大的出现次数的情况下,最少需要的操作次数。
字符串 \(T\) 在 \(S\) 中的「出现次数」,即为能选出最大 \(i\) 的数量,使得 \(S[i, i + |T| - 1]\) 与 \(T\) 完全相同。
思路
先想一下如何求第一问。
直接设 \(f_{i,j,k}\) 表示前 \(i\) 个数填了 \(j\) 个 \(0\),在 KMP 自动机上走到 \(k\) 的位置最大能匹配多少。
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
int n,m,g[N][2],st[N],cnt,o;
pair<int,int>f[2][N][N],ans,x;
string s,t;
signed main()
{cin >> s >> t; n = s.size(); m = t.size();s = ' '+s; t = ' '+t;for(int i = 0;i <= m;i++)//填到第i个数,下一个填0/1,最多能匹配到t的那一段 {//枚举最长匹配 for(int j = i+1;j;j--) if(t[j] == '0'){o = 1; for(int k = j-1;k;k--) o &= (t[i-j+1+k] == t[k]); if(o){g[i][0] = j; break;}} //匹配成功就break for(int j = i+1;j;j--) if(t[j] == '1'){o = 1; for(int k = j-1;k;k--) o &= (t[i-j+1+k] == t[k]); if(o){g[i][1] = j; break;}} }for(int i = 1;i <= n;i++)if(s[i] == '0') st[++cnt] = i;for(int i = 0;i <= 1;i++)for(int j = 0;j <= cnt;j++)for(int z = 0;z <= m;z++)f[i][j][z] = make_pair(-1e9,0);f[0][0][0] = make_pair(0,0); ans = make_pair(-1e9,0);for(int i = 0;i < n;i++){for(int j = 0;j <= cnt;j++)for(int z = 0;z <= m;z++)f[!(i&1)][j][z] = make_pair(-1e9,0);for(int j = 0;j <= cnt;j++)for(int z = 0;z <= m;z++){x = f[(i&1)][j][z]; x.first += (g[z][1] == m);f[!(i&1)][j][g[z][1]] = max(f[!(i&1)][j][g[z][1]],x);if(j < cnt) {x = f[i&1][j][z]; x.second = x.second-abs(i+1-st[j+1]); x.first += (g[z][0] == m);f[!(i&1)][j+1][g[z][0]] = max(f[!(i&1)][j+1][g[z][0]],x);}}}for(int i = 0;i <= m;i++) ans = max(ans,f[(n&1)][cnt][i]);cout << ans.first << " " << -ans.second << '\n';return 0;
}
/*
对于一个串S和新串S1,并且S1是由S每次交换两个相邻位置转移的
则操作次数为abs(a_i-b_i),a_i 为S中0第i次出现的位置,b_i 为S1中0第i次出现的位置
这个很显然,因为只有0/1两种值,0的位置摆好了,1的位置也就自动摆好了,这样也一定是最优的,可以自己画图证,也可以归纳证明。
*/