题意:现在有一个由 A 和 B 两种字符组成的字符串 \(s\ (1\le|s|\le2\cdot 10^5)\)。操作一,可以将 AB 转化为 BC;操作二,可以将 BA 转化为 CB。问最多可以执行上述操作多少次。给出最多操作次数。
思路:
从题面可以看出,本题的两种操作都可以看做是对 B 字符的移动,操作一是向左移动,操作二是向右移动,并且只能单方向移动。有了这个性质,题目就转化为了怎么选择每一个 B 字符的移动方向可以尽可能多的经过 A 字符;
不难发现,如果字符串的边缘有 B 字符或者有至少两个连续的 B 字符,就一定可以将所有的 A 字符都经过。反之,就是单独的 B 字符将一个完整的 A 串切割开来的情景(特判没有 B 字符切割 A 字符的情况),此时就是小学学到的线段模型。由于线段一定比端点多一份,为了最大化经过的 A 字符数量,选择长度最短的 A 子串不经过即可。
T=int(input())for_inrange(T):s=input()ifs.count('BB')ors[0]=='B'ors[-1]=='B':print(s.count('A'))elifs.count('A')==len(s):print(0)else:ans=s.count('A')sub_length=len(s)# 最短 A 串长度i=0whilei<len(s):ifs[i]=='A':j=iwhilej<len(s)ands[j]=='A':j+=1sub_length=min(sub_length,j-i)i=jelse:i+=1ans-=sub_lengthprint(ans)
#include<bits/stdc++.h>usingnamespacestd;#define int long longintn,k;strings="DKER EPH VOS GOLNJ ER RKH HNG OI RKH UOPMGB CPH VOS FSQVB DLMM VOS QETH SQB";stringt1="DKER EPH VOS GOLNJ UKLMH QHNGLNJ A";stringt2="AB CPH VOS FSQVB DLMM VOS QHNG A";stringt3="AB";// 记录每一层构造出来的字符串 Si 的长度 len,当前递归的层数 i (i>=1),对于当前层数需要查询的字符的下标 posvoiddfs(vector<int>&len,inti,intpos,bool&ok){// 已经搜到答案了就不断返回if(ok){return;}// 如果还没有搜到答案,并且已经递归到了最开始的一层,就输出原始字符串相应位置的字符即可if(!i){cout<<s[pos-1];return;}intl1=t1.size(),l2=l1+len[i-1],l3=l2+t2.size(),l4=l3+len[i-1];if(pos<=l1){cout<<t1[pos-1];ok=true;return;}elseif(pos<=l2){dfs(len,i-1,pos-l1,ok);}elseif(pos<=l3){cout<<t2[pos-l2-1];ok=true;return;}elseif(pos<=l4){dfs(len,i-1,pos-l3,ok);}else{cout<<t3[pos-l4-1];ok=true;return;}}voidsolve(){cin>>n>>k;vector<int>len(n+10);len[0]=s.size();for(inti=1;i<=n;i++){len[i]=2*len[i-1]+t1.size()+t2.size()+t3.size();len[i]=min(len[i],(int)2e18);// 点睛之笔...}// 特判下标越界的情况if(k>len[n]){cout<<".";return;}// 否则开始从第n层开始递归搜索boolok=false;dfs(len,n,k,ok);}signedmain(){intT=1;cin>>T;while(T--){solve();}return0;}
constintN=100010;structnode{intid;intw;};intn,m,f[N];// f[i] 表示从根结点到 i 号结点的所有边权的异或值vector<node>G[N];boolvis[N];voiddfs(intfa){if(!vis[fa]){vis[fa]=true;for(auto&ch:G[fa]){f[ch.id]=f[fa]^ch.w;dfs(ch.id);}}}voidsolve(){cin>>n;for(inti=0;i<n-1;i++){inta,b,w;cin>>a>>b>>w;G[a].push_back({b,w});G[b].push_back({a,w});}dfs(1);cin>>m;while(m--){intu,v;cin>>u>>v;cout<<(f[u]^f[v])<<"\n";}}
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=25;inta[N],res;voidfun(intn){intMIN=20*60;for(inti=0;i<=(1<<n);i++){intl=0,r=0;for(intj=0;j<n;j++){if(i&(1<<j))r+=a[j];elsel+=a[j];}MIN=min(MIN,max(l,r));}res+=MIN;}voidsolve(){intx[4]{};for(inti=0;i<4;i++)cin>>x[i];for(inti=0;i<4;i++){for(intj=0;j<x[i];j++)cin>>a[j];fun(x[i]);}cout<<res<<"\n";}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=15;intn;intres=1e9;struct{intl,r;}a[N];voidsolve(){cin>>n;for(inti=0;i<n;i++)cin>>a[i].l>>a[i].r;for(inti=0;i<=(1<<n);i++){// 特判没有调料的情况 intcnt=0;for(intj=0;j<n;j++)if(i&(1<<j))cnt++;if(!cnt)continue;// 计算两个味道的差值intls=1,rs=0;for(intj=0;j<n;j++)if(i&(1<<j))ls*=a[j].l,rs+=a[j].r;res=min(res,abs(ls-rs));}cout<<res<<"\n";}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=15;intn;intres=1e9;struct{intl,r;}a[N];// 当前决策元素的下标idx,是否被选择choose,酸度之积ls,苦度之和rs voiddfs(intidx,boolchoose,intls,intrs){if(idx==n){if(ls==1&&rs==0)return;res=min(res,abs(ls-rs));return;}if(choose){ls*=a[idx].l;rs+=a[idx].r;}dfs(idx+1,false,ls,rs);dfs(idx+1,true,ls,rs);}voidsolve(){cin>>n;for(inti=0;i<n;i++)cin>>a[i].l>>a[i].r;dfs(0,false,1,0);dfs(0,true,1,0);cout<<res<<"\n";}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=10;intn,m,k;intaa,bb,cc,dd;intg[N][N],vis[N][N];intres;intdx[]={-1,1,0,0},dy[]={0,0,1,-1};voiddfs(intx,inty){if(x==cc&&y==dd){res++;return;}for(intk=0;k<4;k++){intxx=x+dx[k],yy=y+dy[k];if(xx>0&&xx<=n&&yy>0&&yy<=m&&!g[xx][yy]&&!vis[xx][yy]){vis[x][y]=true;dfs(xx,yy);vis[x][y]=false;}}}voidsolve(){cin>>n>>m>>k;cin>>aa>>bb>>cc>>dd;while(k--){intx,y;cin>>x>>y;g[x][y]=1;}dfs(aa,bb);cout<<res<<"\n";}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
#include<bits/stdc++.h>#define int long longusingnamespacestd;intn;vector<int>res;// now 表示当前结点的值,sum 表示根到当前结点的路径之和voiddfs(intnow,intsum){if(sum>n)return;if(sum==n){for(inti=0;i<res.size();i++)cout<<res[i]<<"+\n"[i==res.size()-1];return;}for(inti=now;i<n;i++){res.push_back(i);dfs(i,sum+i);res.pop_back();}}voidsolve(){cin>>n;for(inti=1;i<n;i++){res.push_back(i);dfs(i,i);res.pop_back();}}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=110;intn,m;charg[N][N];boolvis[N][N];intres,dx[]={1,-1,0,0,1,1,-1,-1},dy[]={0,0,1,-1,1,-1,1,-1};voiddfs(inti,intj){if(i<1||i>n||j<1||j>m||vis[i][j]||g[i][j]!='W')return;vis[i][j]=true;for(intk=0;k<8;k++){intx=i+dx[k],y=j+dy[k];dfs(x,y);}}voidsolve(){cin>>n>>m;for(inti=1;i<=n;i++)for(intj=1;j<=m;j++)cin>>g[i][j];for(inti=1;i<=n;i++)for(intj=1;j<=m;j++)if(!vis[i][j]&&g[i][j]=='W')dfs(i,j),res++;cout<<res<<"\n";}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=110;intn,m;charg[N][N];boolvis[N][N];intres,dx[]={1,-1,0,0,1,1,-1,-1},dy[]={0,0,1,-1,1,-1,1,-1};voidbfs(inti,intj){queue<pair<int,int>>q;q.push({i,j});vis[i][j]=true;while(q.size()){autoh=q.front();q.pop();intx=h.first,y=h.second;for(intk=0;k<8;k++){intxx=x+dx[k],yy=y+dy[k];if(!vis[xx][yy]&&g[xx][yy]=='W'){q.push({xx,yy});vis[xx][yy]=true;}}}}voidsolve(){cin>>n>>m;for(inti=1;i<=n;i++)for(intj=1;j<=m;j++)cin>>g[i][j];for(inti=1;i<=n;i++)for(intj=1;j<=m;j++)if(!vis[i][j]&&g[i][j]=='W')bfs(i,j),res++;cout<<res<<"\n";}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=35;intn,g[N][N];intdx[]={0,0,1,-1},dy[]={1,-1,0,0};boolvis[N][N];voiddfs(inti,intj){if(i<1||i>n||j<1||j>n||g[i][j]==1||vis[i][j])return;vis[i][j]=true;for(intk=0;k<4;k++){intx=i+dx[k],y=j+dy[k];dfs(x,y);}}voidsolve(){cin>>n;for(inti=1;i<=n;i++)for(intj=1;j<=n;j++)cin>>g[i][j];for(inti=1;i<=n;i++)if(g[1][i]==0&&!vis[1][i])dfs(1,i);for(inti=1;i<=n;i++)if(g[i][n]==0&&!vis[i][n])dfs(i,n);for(inti=1;i<=n;i++)if(g[n][i]==0&&!vis[n][i])dfs(n,i);for(inti=1;i<=n;i++)if(g[i][1]==0&&!vis[i][1])dfs(i,1);for(inti=1;i<=n;i++)for(intj=1;j<=n;j++)if(vis[i][j])cout<<0<<" \n"[j==n];elseif(g[i][j]==0)cout<<2<<" \n"[j==n];elsecout<<g[i][j]<<" \n"[j==n];}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=410;structIdx{intx,y;};intn,m,x,y;intd[N][N];intdx[]={1,1,-1,-1,2,2,-2,-2},dy[]={2,-2,2,-2,1,-1,1,-1};voidbfs(){queue<Idx>q;q.push({x,y});d[x][y]=0;while(q.size()){autoh=q.front();q.pop();for(intk=0;k<8;k++){inti=h.x+dx[k],j=h.y+dy[k];if(i<1||i>n||j<1||j>m||d[i][j]!=-1)continue;d[i][j]=d[h.x][h.y]+1;q.push({i,j});}}}voidsolve(){cin>>n>>m>>x>>y;for(inti=1;i<=n;i++)for(intj=1;j<=m;j++)d[i][j]=-1;bfs();for(inti=1;i<=n;i++)for(intj=1;j<=m;j++)cout<<d[i][j]<<" \n"[j==m];}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=210;intn,x,y,a[N];intd[N];// d[i] 表示起点到第 i 层楼的最小操作次数boolvis[N];voidbfs(){queue<int>q;q.push(x);d[x]=0;vis[x]=true;while(q.size()){intnow=q.front();q.pop();if(now==y)break;inthigh=now+a[now],low=now-a[now];if(!vis[high]&&high>=1&&high<=n){q.push(high);d[high]=d[now]+1;vis[high]=true;}if(!vis[low]&&low>=1&&low<=n){q.push(low);d[low]=d[now]+1;vis[low]=true;}}}voidsolve(){cin>>n>>x>>y;for(inti=1;i<=n;i++){cin>>a[i];d[i]=-1;}bfs();cout<<d[y]<<"\n";}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
【dfs/状压dp】吃奶酪
题意:给定一个平面直角坐标系与 n 个点的坐标,起点在坐标原点。问如何选择行进路线使得到达每一个点且总路程最短
- 思路一:爆搜。题中的 \(n \le 15\) 直接无脑爆搜,但是 TLE。爆搜的思路为:每次选择其中的一个点,接下来选择剩余的没有被选择过的点继续搜索,知道所有的点全部都搜到为止
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=20;intn;doubleres=4000.0;boolvis[N];structIdx{doublex,y;}a[N];doubled(Idxbe,Idxen){returnsqrt((be.x-en.x)*(be.x-en.x)+(be.y-en.y)*(be.y-en.y));}// 父结点坐标 fa,当前结点次序 now,当前路径长度 len voiddfs(Idxfa,intnow,doublelen){vis[now]=true;if(count(vis+1,vis+n+1,true)==n){res=min(res,len);}for(inti=1;i<=n;i++)if(!vis[i])dfs(a[now],i,len+d(a[now],a[i]));vis[now]=false;}voidsolve(){cin>>n;for(inti=1;i<=n;i++){cin>>a[i].x>>a[i].y;}for(inti=1;i<=n;i++){Idxfa={0,0};dfs(fa,i,d(fa,a[i]));}cout<<fixed<<setprecision(2)<<res<<"\n";}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
#include<bits/stdc++.h>#define int long longusingnamespacestd;intn;voidsolve(){cin>>n;for(inti=0;i<(1<<n);i++){for(intj=0;j<n;j++){if(i&(1<<j)){cout<<j+1<<' ';}}cout<<"\n";}}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
#include<bits/stdc++.h>#define int long longusingnamespacestd;intn;vector<int>a;voiddfs(intnow,boolcho){if(now==n){for(auto&x:a){cout<<x<<' ';}cout<<"\n";return;}dfs(now+1,false);a.push_back(now+1);dfs(now+1,true);a.pop_back();}voidsolve(){cin>>n;dfs(1,false);a.push_back(1);dfs(1,true);a.pop_back();}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=10;intn;boolvis[N];vector<int>a;// 当前数位 nowvoiddfs(intnow){if(now>n){for(auto&x:a){cout<<x<<' ';}cout<<"\n";return;}for(inti=1;i<=n;i++){if(!vis[i]){a.push_back(i);vis[i]=true;dfs(now+1);a.pop_back();vis[i]=false;}}}voidsolve(){cin>>n;dfs(1);}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
struct node { int to, w; };
vector<vector<node>> g(n, vector<node>());
for (auto e: edges) {
int u = e[0], v = e[1], w = e[2];
g[u].push_back({v, w});
g[v].push_back({u, w});
}
function<int(int, int, int)> dfs = [&](int fa, int now, int d) {
int res = d % signalSpeed == 0;
for (auto ch: g[now]) {
if (ch.to != fa) {
res += dfs(now, ch.to, d + ch.w);
}
}
return res;
};
vector<int> res(n);
for (int i = 0; i < n; i++) {
int sum = 0;
for (auto ch: g[i]) {
int cnt = dfs(i, ch.to, ch.w);
res[i] += cnt * sum;
sum += cnt;
}
}
return res;
}
};
python []
class Solution:
def countPairsOfConnectableServers(self, edges: List[List[int]], signalSpeed: int) -> List[int]:
n = len(edges) + 1
g = [[] for _ in range(n)]
for u, v, w in edges:
g[u].append((v, w))
g[v].append((u, w))
def dfs(fa: int, now: int, d: int) -> int:
ret = d % signalSpeed == 0
for ch in g[now]:
if ch[0] != fa:
ret += dfs(now, ch[0], d + ch[1])
return ret
res = [0] * n
for i in range(n):
sum = 0
for ch in g[i]:
cnt = dfs(i, ch[0], ch[1])
res[i] += sum * cnt
sum += cnt
return res
```
思路:可以将这道题抽象为求解「将 a 个大于 1 位置的数分配到 b 个 0 位置」的方案中的最小代价问题。容易联想到全排列选数的母问题:数字的位数对应这里的 b 个 0 位置,每个位置可以填的数对应这里的用哪个 a 来填。区别在于:0 的位置顺序不是固定的,用哪个 a 来填的顺序也不是固定的。这与全排列数中:被填的位置顺序是固定的,用哪个数来填不是固定的,有所区别。因此我们可以全排列枚举每一个位置,在此基础之上再全排列枚举每一个位置上可选的 a 进行填充。可以理解为全排列的嵌套。那么最终递归树的深度就是 0 的个数,递归时再用一个参数记录每一个选数分支对应的代价即可。
int res = INT_MAX, n = z.size();
vector<bool> vis(n);
auto dfs = [&](auto&& dfs, int dep, int t) -> void {
if (dep == n) {
res = min(res, t);
return;
}
for (int i = 0; i < n; i++) {
if (vis[i]) continue;
vis[i] = true;
for (auto& [x, y]: a) {
if (g[x][y] <= 1) continue;
g[x][y]--;
dfs(dfs, dep + 1, t + abs(z[i].first - x) + abs(z[i].second - y));
g[x][y]++;
}
vis[i] = false;
}
};
dfs(dfs, 0, 0);
return res;
}
};
cpp [C++库函数]
class Solution {
public:
int minimumMoves(vector>& g) {
vector> z, a;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (!g[i][j]) {
z.push_back({i, j});
} else {
while (g[i][j] > 1) {
a.push_back({i, j});
g[i][j]--;
}
}
}
}
int res = INT_MAX;
do {
int t = 0;
for (int i = 0; i < z.size(); i++) {
t += abs(a[i].first - z[i].first) + abs(a[i].second - z[i].second);
}
res = min(res, t);
} while (next_permutation(a.begin(), a.end()));
return res;
}
};
```
```python []
class Solution:
def minimumMoves(self, g: List[List[int]]) -> int:
a, z = [], []
for i in range(3):
for j in range(3):
if not g[i][j]:
z.append((i, j))
elif g[i][j] > 1:
a.append((i, j))
1 2 3 4 5 6 7 8 910111213141516171819202122
res = 1000
n = len(z)
vis = [False] * n
def dfs(dep: int, t: int) -> None:
nonlocal res
if dep == n:
res = min(res, t)
return
for i in range(n):
if vis[i]: continue
vis[i] = True
for x, y in a:
if g[x][y] <= 1: continue
g[x][y] -= 1
dfs(dep + 1, t + abs(z[i][0] - x) + abs(z[i][1] - y))
g[x][y] += 1
vis[i] = False
dfs(0, 0)
return res
python [Python库函数]
class Solution:
def minimumMoves(self, g: List[List[int]]) -> int:
from itertools import permutations
a, z = [], []
for i in range(3):
for j in range(3):
if not g[i][j]:
z.append((i, j))
while g[i][j] > 1:
a.append((i, j))
g[i][j] -= 1
res, n = 1000, len(a)
for p in permutations(a):
t = 0
for i in range(n):
t += abs(p[i][0] - z[i][0]) + abs(p[i][1] - z[i][1])
res = min(res, t)
return res
```
#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=1000010;intn,a[N],t[N];intcnt;// 逆序数 voidMergeSort(intl,intr){if(l>=r)return;intmid=(l+r)>>1;MergeSort(l,mid),MergeSort(mid+1,r);inti=l,j=mid+1,idx=0;while(i<=mid&&j<=r){if(a[i]<a[j])t[idx++]=a[i++];else{cnt+=mid-i+1;t[idx++]=a[j++];}}while(i<=mid)t[idx++]=a[i++];while(j<=r)t[idx++]=a[j++];for(i=l,idx=0;i<=r;i++,idx++)a[i]=t[idx];}voidsolve(){cin>>n;for(inti=0;i<n;i++)cin>>a[i];MergeSort(0,n-1);intres;if(n%2==1){if(cnt%2)res=1;elseres=2;}else{if(cnt%2)res=2;elseres=1;}cout<<res<<"\n";}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}