【CF67C】Sequence of Balls
作者:互联网
样例弱得一批。模拟赛T2,上演了大型fst现场()。
题意:
给定两个长度不超过 \(4000\) 的字符串 \(s,t\),可以进行若干次下面的操作:
- 花费 \(a\) 的代价,在 \(s\) 的一个位置添加一个任意字符。
- 花费 \(b\) 的代价,删除 \(s\) 的一个字符。
- 花费 \(c\) 的代价,修改 \(s\) 的一个字符。
- 花费 \(d\) 的代价,交换 \(s\) 的两个相邻的字符。
其中保证 \(a+b \le 2d\)。
问最少的代价,把 \(s\) 变成 \(t\)。
\(1 \le a,b,c,d \le 100\)。
分析:
如果只有前三种操作那是一个 trival 的题。
交换操作是本题最大的毒瘤。
结论:
\(1.\) 一个字符,如果它是被创造的,那么不会再被操作(交换也属于操作)。一个字符如果被替换过一次,那么一定不会再对它操作。
证明:如果创造过后被删除,没有任何意义。如果创造过后被修改,为什么不创造的时候就修改。如果创造过后被交换,比如说本来有一个字符 \(b\),然后前面创造一个字符 \(a\),得到 \(ab\),交换得到 \(ba\)。那为什么不直接一开始在 \(b\) 的后面创造字符。
如果一个字符原来存在,然后被修改了,显然删除它和再次修改它没有任何意义。考虑被修改后交换,则代价为 \(c+d\),比如说原来为 \(bc\),我们修改成 \(ac\),交换得到 \(ca\),首先发现 \(a+b \le 2d\),如果 \(c \ge d\),那么我们直接删除 \(b\),在 \(c\) 后面加入一个 \(a\),代价为 \(a+b \le 2d \le c+d\)。如果 \(c \le d\),我们直接把 \(bc\) 做两次替换得到 \(ca\),代价为 \(2c \le 2d\)。
这个结论告诉我们什么?告诉我们,我们只会交换 \(s\) 中本来存在的字符。
\(2.\) 如果 \(s_1\) 和 \(s_2\) 交换了,则这两个字符不会再被交换。也不会再被修改
证明:先说明不会被交换,不妨采用反证。不失一般性,假设交换后,\(s_2\) 位置(字符是原来的 \(s_1\))又和 \(s_3\) 交换了。即 \(abc\),先变成 \(bac\),然后变成 \(bca\)。
然后你发现其实可以通过删除最前面的 \(a\),加入最后面的 \(c\) 来实现,代价是 \(a+b \le 2d\)。
然后再说明不会被修改。如果我们交换 \(ab\) 变成 \(ba\)。首先考虑只修改一个字符的情况,容易发现这是无意义的,一次删除+一次添加(创造)就能实现同样效果且花费更小。再来考虑两个字符都被修改的情况,代价是 \(d+2c\)。那为什么不交换前就修改好,花费 \(2c\) 代价呢。
做法:
模拟赛时,我 yy 出了这两个结论。正常人到这里,都能 AC 了,但是我还是 fst 了 /kk。
还是设 \(f(i,j)\) 为 \(s\) 的前 \(i\) 个字符和 \(t\) 的前 \(j\) 个字符相等的最少代价。前三种转移非常简单:
- 添加:\(f(i,j)=f(i,j-1)+a\)。
- 删除:\(f(i,j)=f(i-1,j)+ b\)。
- 修改:\(f(i,j)=f(i-1,j-1)+c\)。
- 特殊地,\(s_i=t_j\) 的时候,额外考虑 \(f(i,j)=f(i-1,j-1)\)。
然后考虑加入第四种操作。根据结论 \(1\) 和结论 \(2\)。我们会选择 \(s_i\) 之前的一个字符 \(s_k\),把 \(s_{k+1}\sim s_{i-1}\) 的字符删掉(一位神仙的 fst 原因), 交换 \(s_k\) 和 \(s_i\)。然后再在它们之间添加若干个字符(我的fst原因)。根据结论 \(2\),这两个字符不能被修改。那么 \(s_k\) 必须等于 \(t_j\)。设 \(s_i\) 和 \(t_y\) 匹配,那么 \(s_i\) 必须等于 \(t_y\)。
考虑此时的代价是:\(f(k-1,y-1)+(i-k-1)\,\times b+(j-y-1)\times\,a\)。
我们发现,对于一个固定的 \(i,j\) 来说,会尽可能让 \(k\) 和 \(y\) 尽可能的大。所以我们预处理一个 \(g(i,j)\),维护一个 pair,储存对应的 \(k,y\)。计算 \(f(i,j)\) 的时候直接从 \(g(i,j)\) 的信息里转移过来即可。至于 \(g(i,j)\) 的计算,可以通过维护两个桶来实现。
复杂度:\(O(n^2)\)。
#include<bits/stdc++.h>
#define rep(i,a,b) for(ll i=(a);i<=(b);i++)
#define per(i,a,b) for(ll i=(a);i>=(b);i--)
#define op(x) ((x&1)?x+1:x-1)
#define odd(x) (x&1)
#define even(x) (!odd(x))
#define lc(x) (x<<1)
#define rc(x) (lc(x)|1)
#define lowbit(x) (x&-x)
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define next Cry_For_theMoon
#define il inline
#define pb(x) push_back(x)
#define is(x) insert(x)
#define sit set<int>::iterator
#define mapit map<int,int>::iterator
#define pi pair<int,int>
#define ppi pair<int,pi>
#define pp pair<pi,pi>
#define fr first
#define se second
#define vit vector<int>::iterator
#define mp(x,y) make_pair(x,y)
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double db;
using namespace std;
const int MAXN=4010,INF=1e9;
int a,b,c,d,n,m,f[MAXN][MAXN];
pi g[MAXN][MAXN];
int bucket1[26],bucket2[26];
char s[MAXN],t[MAXN];
void calc(int i,int j){
if(s[i]==t[j])f[i][j]=Min(f[i][j],f[i-1][j-1]);
//1.插入
f[i][j]=Min(f[i][j],a+f[i][j-1]);
//2.删除
f[i][j]=Min(f[i][j],b+f[i-1][j]);
//3.替换
f[i][j]=Min(f[i][j],c+f[i-1][j-1]);
//4.交换
pi zero=mp(0,0);
if(g[i][j]!=zero){
int x=g[i][j].fr,y=g[i][j].se;
//sx和si交换
//sx对应tj,si对应ty
int cost=d+(i-x-1)*b+(j-y-1)*a;
f[i][j]=Min(f[i][j],f[x-1][y-1]+cost);
}
}
int main(){
scanf("%d%d%d%d",&a,&b,&c,&d);
scanf("%s%s",s+1,t+1);
n=strlen(s+1);
m=strlen(t+1);
rep(i,0,n)rep(j,0,m)f[i][j]=INF,g[i][j]=mp(0,0);
f[0][0]=0;
rep(i,1,n)f[i][0]=i*b;
rep(i,1,m)f[0][i]=i*a;
rep(i,1,n){
memset(bucket2,0,sizeof bucket2);
rep(j,1,m){
if(bucket1[t[j]-'a'] && bucket2[s[i]-'a']){
g[i][j]=mp(bucket1[t[j]-'a'],bucket2[s[i]-'a']);
}
bucket2[t[j]-'a']=j;
}
bucket1[s[i]-'a']=i;
}
rep(i,1,n){
rep(j,1,m){
calc(i,j);
}
}
printf("%d",f[n][m]);
return 0;
}
最后模拟赛还是 T1 + T3 200 pts 滚出了,555
标签:字符,Balls,Sequence,int,rep,交换,le,CF67C,define 来源: https://www.cnblogs.com/Cry-For-theMoon/p/15132227.html