ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【CF67C】Sequence of Balls

2021-08-12 13:35:02  阅读:258  来源: 互联网

标签:字符 Balls Sequence int rep 交换 le CF67C define


传送门

样例弱得一批。模拟赛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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有