1860D Balanced String
首先只能是0和1交换,1在 i i i位置,0在 j j j位置,每交换一次产生的贡献是 2 ∗ ( i − j ) 2*(i-j) 2∗(i−j),所以我们可以先算出原01串中所需要的贡献 m m m,我们发现找到 t o l tol tol 个1和0的位置 i k , j k i_k,j_k ik,jk 且 ∑ k t o l i k − j k = m \sum_{k}^{tol} i_k-j_k=m ∑ktolik−jk=m,我们可以拆开 ∑ k t o l i k − ∑ k t o l j k = m \sum_{k}^{tol} i_k- \sum_{k}^{tol} j_k=m ∑ktolik−∑ktoljk=m,然后分别dp出选tol个数,0,1的位置和分别有那些状态可以达到,易证位置和小于 n 2 n^2 n2,然后枚举 t o l tol tol,枚举1的位置和,算出0的位置和,判断两个状态是否能达到
时间复杂度 O ( n 4 ) O(n^4) O(n4)
void solve(){
std::string s;
std::cin>>s;
int n=s.length();
std::vector<int> a(n+1);
int sum=0,m=0;
for (int i=1;i<=n;i++){
a[i]=s[i-1]-'0';
if (a[i]){
m-=i-1-sum;
}else{
m+=sum;
}
sum+=a[i];
}
m>>=1;
std::vector<std::vector<int>> dp0(n+1,std::vector<int>(n*n+1)),dp1(n+1,std::vector<int>(n*n+1));
dp0[0][0]=dp1[0][0]=1;
for (int i=1;i<=n;i++){
for (int j=i;j>=1;j--){
for (int k=n*n;k>=i;k--){
if (a[i]){
dp1[j][k]|=dp1[j-1][k-i];
}else{
dp0[j][k]|=dp0[j-1][k-i];
}
}
}
}
m=-m;
for (int i=0;i<=n;i++){
for (int j=0;j<=n*n;j++){
int k=j-m;
if (k>=0&&k<=n*n&&dp1[i][j]&&dp0[i][k]){
std::cout<<i;
return;
}
}
}
}
1860E Fast Travel Text Editor
首先注意到是小写字母,说明最多 26 * 26 种组合方式,然后发现题意每次操作代价都为1,考虑建图,发现连边和对点的定义不好搞,考虑bfs,定义 d i s i , j , x dis_{i,j,x} disi,j,x,表示当前点 x x x,到某个形如 ′ a ′ + i , ′ a ′ + j 'a'+i,'a'+j ′a′+i,′a′+j位置的最小距离,这样我们每次询问只要枚举 26 * 26 次,类似Floyed找中转点的方法, m i n ( y − x , d i s i , j , x + d i s i , j , y + 1 ) min(y-x,dis_{i,j,x}+dis_{i,j,y}+1) min(y−x,disi,j,x+disi,j,y+1)。
我们枚举每个 i , j i,j i,j,然后从形如 ′ a ′ + i , ′ a ′ + j 'a'+i,'a'+j ′a′+i,′a′+j的位置出发,bfs向外扩展,更新各点的 d i s i , j , x dis_{i,j,x} disi,j,x,每次扩展除了到 x + 1 x+1 x+1和 x − 1 x-1 x−1点外,还要让 x x x通过第三种操作跳跃到其它点,由于每个点最多入队一次,所以时间复杂度为 O ( 2 6 2 ∣ s ∣ ) O(26^2\vert s \vert) O(262∣s∣)
总时间复杂度 O ( 2 6 2 ( m + ∣ s ∣ ) ) O(26^2 (m+\vert s \vert)) O(262(m+∣s∣))
const int inf=1e9;
void solve(){
std::string s;
std::cin>>s;
int n=s.length();
std::vector<int> pos[26][26];
for (int i=1;i<n;i++){
pos[s[i-1]-'a'][s[i]-'a'].push_back(i);
}
std::vector dis(26,std::vector(26,std::vector(n+2,inf)));
for (int i=0;i<26;i++){
for (int j=0;j<26;j++){
std::queue<int> q;
for (auto x:pos[i][j]){
q.push(x);
dis[i][j][x]=0;
}
std::vector<std::vector<int>> vis(26,std::vector<int>(26));
vis[i][j]=1;
while (!q.empty()){
int x=q.front();
q.pop();
if (x-1>=1&&dis[i][j][x-1]==inf){
dis[i][j][x-1]=dis[i][j][x]+1;
q.push(x-1);
}
if (x+1<n&&dis[i][j][x+1]==inf){
dis[i][j][x+1]=dis[i][j][x]+1;
q.push(x+1);
}
int l=s[x-1]-'a',r=s[x]-'a';
if (!vis[l][r]){
vis[l][r]=1;
for (auto v:pos[l][r]){
if (dis[i][j][v]==inf){
dis[i][j][v]=dis[i][j][x]+1;
q.push(v);
}
}
}
}
}
}
int m;
std::cin>>m;
while (m--){
int x,y;
std::cin>>x>>y;
int ans=abs(x-y);
for (int i=0;i<26;i++){
for (int j=0;j<26;j++){
ans=std::min(ans,dis[i][j][x]+dis[i][j][y]+1);
}
}
std::cout<<ans<<"\n";
}
}