题意:现在有一个由 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)
fromcollectionsimportdefaultdictfromtypingimportList,Tuplefromitertoolsimportcombinations,permutationsimportmath,heapq,queueII=lambda:int(input())FI=lambda:float(input())MII=lambda:tuple(map(int,input().split()))LII=lambda:list(map(int,input().split()))defsolve()->None:n=II()s=[0]*(n+1)pos,neg=0,0foriinrange(1,n+1):s[i]=II()foriinrange(2,n+1):x=s[i]-s[i-1]ifx>0:pos+=xelse:neg+=xprint(f"{max(pos,abs(neg))}\n{abs(pos-abs(neg))+1}")if__name__=='__main__':T=1# T = II()whileT:solve();T-=1
#include<bits/stdc++.h>#define int long long usingnamespacestd;constintN=1e5+10;intn,k;inta[N];boolchk(intx){intsum=0;for(inti=0;i<n;i++)sum+=a[i]/x;returnsum>=k;}voidsolve(){cin>>n>>k;intsum=0;for(inti=0;i<n;i++){cin>>a[i];sum+=a[i];}intl=1,r=1e8;while(l<r){intmid=(l+r+1)>>1;if(chk(mid))l=mid;elser=mid-1;}if(k>sum)cout<<"0\n";elsecout<<r<<"\n";}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
题意:给定 n 个递增的不重复数,现在可以从其中拿掉 k 个数,使得相邻数字之间的最小差值最大,问最大的最小差值是多少
思路:二分答案。将答案看做 y 轴,拿掉的数的数量看做 x 轴,就是二分 y 值。可以发现拿的数字越多,最小差值就越大,具有单调性,可以二分。我们直接二分答案,即直接二分最小差值的具体数值,通过判断当前的最小差值至少需要拿掉多少个数才能满足,进行 check 操作。至于如何计算至少要拿掉的数字,我们采用右贪心准则,即检查当前点与上一个点之间的距离是否满足最小差值的要求,如果不满足就需要记数,为了便于后续的计算,直接将当前的下标用上一个点的下标覆盖掉即可
#include<bits/stdc++.h>#define int long long usingnamespacestd;constintN=5e4+10;intlim,n,k;inta[N],b[N];booldel[N];boolok(intx){intcnt=0;memset(del,false,sizeofdel);for(inti=1;i<=n;i++){b[i]=a[i];}for(inti=1;i<=n;i++){if(b[i]-b[i-1]<x){del[i]=true;b[i]=b[i-1];cnt++;}}if(lim-b[n]<x){cnt++;}returncnt<=k;}voidsolve(){cin>>lim>>n>>k;for(inti=1;i<=n;i++)cin>>a[i];intl=1,r=lim;while(l<r){intmid=(l+r+1)>>1;if(ok(mid))l=mid;elser=mid-1;}cout<<r<<"\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 long usingnamespacestd;constintN=1e6;intlim,n,k;inta[N];boolchk(intx){intcnt=0;for(inti=1;i<n;i++){intgap=a[i]-a[i-1];if(gap>x){cnt+=(gap+x-1)/x-1;}}returncnt>k;}voidsolve(){cin>>lim>>n>>k;for(inti=0;i<n;i++){cin>>a[i];}intl=1,r=lim;while(l<r){intmid=(l+r)>>1;if(chk(mid))l=mid+1;elser=mid;}cout<<r<<"\n";}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
思路:二分答案,将答案看做 y 轴,拿掉的数的数量看做 x 轴,就是二分 y 值。可以发现,分的段数越多,所有分段和的最大值就越小,具有单调性,可以二分。我们直接二分答案,即直接二分分段最大值,通过判断当前最大值的约束条件下可以分的组数进行判断。至于如何计算当前最大值条件下可分得的组数,直接线性扫描进行局部求和即可
#include<bits/stdc++.h>#define int long long usingnamespacestd;constintN=1e5+10;intn,k;inta[N];// 当前分组时最大子段和为 x boolchk(intx){intcnt=0;for(inti=0,s=0;i<n;i++){if(a[i]>x)returntrue;if(s+a[i]<=x)s+=a[i];else{cnt++;s=a[i];}}cnt+=1;returncnt>k;}voidsolve(){cin>>n>>k;for(inti=0;i<n;i++){cin>>a[i];}intl=0,r=1e9;while(l<r){intmid=(l+r)>>1;if(chk(mid))l=mid+1;elser=mid;}cout<<r<<"\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=100010;intn;doublep,v[N],s[N];boolchk(doublex){// x 为当前状态期望使用的时间 doubleneed=0;for(inti=1;i<=n;i++)if(v[i]*x>s[i])need+=v[i]*x-s[i];returnneed<=x*p;}voidsolve(){cin>>n>>p;for(inti=1;i<=n;i++){cin>>v[i]>>s[i];}doublel=0,r=1e10+10;while(r-l>1e-6){doublemid=(l+r)/2;if(chk(mid))l=mid;elser=mid;}if(r>1e10)cout<<-1<<"\n";elsecout<<r<<"\n";}signedmain(){ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);intT=1;// cin >> T;while(T--)solve();return0;}
思路:本题一眼二分图问题,但是有些变化的是左右部并非散点图,其中是有连边的。如何求出最小边权呢?我们可以这么想,首先答案一定出自左右部的连边中(除非左右部全是散点,那答案就是 0),之所以可以采用二分图将点集分为两部分,是因为我们在某种规则下忽略了其中奇数环(二分图定理)的一些边。当规则定义为 忽略边权不超过 x 的边时,该图若可以二分,那么忽略边权比 x 值更大的边时,该图同样一定也可以二分,反之则不一定可以二分(特性图如下)。具备单调性,于是我们可以通过 二分阈值、检查图是否可二分 的方法来计算出答案
思路:可以发现,想要序列尽可能的长,那么需要放置的棋子就要尽可能的多,具备单调性,可以二分。我们二分答案,即最长序列长度。对于已知的 k 个可放置棋子,我们需要找到最大的序列长度,于是我们套用寻找右边界模板。检查方法就是判断对于当前的长度,通过前缀和与滑动窗口的形式计算当前窗口内需要放置多少颗棋子才能连为一体:
#include<iostream>usingnamespacestd;#define int long longintn,res;voiddfs(intx){if(x>n)return;res++;dfs(x*10+4);dfs(x*10+7);}signedmain(){cin>>n;dfs(4);dfs(7);cout<<res<<"\n";return0;}
#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;}
#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;}