[ABC227E] Swap 题解
考试一道题题解。
30pts:枚举所有串,\(check\) 是否可行。
60pts:做 \(bfs\),暴力推演变化过程,用 \(map\) 去重,时间复杂度 \(O(nC_{n}^{n/3}C_{n-n/3}^{n/3})\)。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
unordered_map<string,int>mp;
string s;int k;
ll ans=1;
struct zjy{
string s;int b;
};queue<zjy>q;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>s>>k;mp[s]=1;
q.push({s,0});
while(q.size()){
int b=q.front().b+1;
s=q.front().s;q.pop();
if(b>k) continue;
for(int i=1;s[i];i++){
swap(s[i-1],s[i]);
if(!mp[s])
mp[s]=1,q.push({s,b}),ans++;
swap(s[i-1],s[i]);
}
}cout<<ans;
return 0;
}
100pts:
考虑到同种字符相对位置不可能发生改变,所以可以直接一个一个加入字符,然后加上将他移动到这里的代价。
设 \(dp_{i,j,k,l}\) 表示前 \(i+j+k\) 位用了 \(i\) 个 \(K\),\(j\) 个 \(E\),\(k\) 个 \(Y\),转换了 \(l\) 次时的可能性。
转移方程详见代码,时间复杂度 \(O(n^5)\)(\(K\) 超过 \(\frac{sz(sz-1)}{2}\) 就是在走倒退)。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
string s;int k,n,m,y;
int a[35],b[35],c[35];
ll dp[35][35][35][605],ans;
int sm1[35],sm2[35],sm3[35];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>s>>k;int sz=s.size();
k=min(k,sz*(sz-1)/2);
for(int i=0;s[i];i++){
sm1[i+1]=sm1[i];
sm2[i+1]=sm2[i];
sm3[i+1]=sm3[i];
if(s[i]=='K')
a[++n]=i+1,sm1[i+1]++;
if(s[i]=='E')
b[++m]=i+1,sm2[i+1]++;
if(s[i]=='Y')
c[++y]=i+1,sm3[i+1]++;
}dp[0][0][0][0]=1;
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
for(int l=0;l<=y;l++)
for(int t=0;t<=k;t++){
if(i<n){
int p=a[i+1],cnt=max(0,sm2[p]-j)+max(0,sm3[p]-l);
//cnt指将第i+1个K移动到第i+j+l+1位所用的代价,下同
dp[i+1][j][l][t+cnt]+=dp[i][j][l][t];
}if(j<m){
int p=b[j+1],cnt=max(0,sm1[p]-i)+max(0,sm3[p]-l);
dp[i][j+1][l][t+cnt]+=dp[i][j][l][t];
}if(l<y){
int p=c[l+1],cnt=max(0,sm1[p]-i)+max(0,sm2[p]-j);
dp[i][j][l+1][t+cnt]+=dp[i][j][l][t];
}if(i+j+l==sz) ans+=dp[i][j][l][t];
}
cout<<ans;
return 0;
}