1 条题解

  • 0
    @ 2026-5-19 11:35:10

    思路

    fl,rf_{l,r} 表示区间 [l,r][l,r] 的最小代价。初始化 fi,i=Af_{i,i}=A

    我们考虑 n3n^3 的做法(是的你没听错跑的飞快)。

    首先预处理 hash,用来判断两个字串是否相等,方便我们判断可否复制。

    我们枚举 l,rl,r 两个端点及其长度 lenlen,考虑 fl,rf_{l,r} 如何被转移,我们直接从前面或者后面加一个字符,代价为 AA,则有 fl,rmin(fl+1,r,fl,r1)+Af_{l,r}\to \min (f_{l+1,r},f_{l,r-1})+A

    我们考虑剪切和复制该如何转移,对于复制和剪切我们从题中可得只更改后面的字符,那么我们只要从 ll 开始进行转移即可,对于区间 [l,r][l,r] 的剪切代价为 BB,然后我们接着又开始枚举一个指针 kk,我们用 hash 判断是否可以复制,如果可以复制我们就直接代价加 CC,然后 kk+len1k\to k+len-1,不可以复制那么就直接代价加 AAkk+1k\to k+1,令总代价为 sumsum,则有 fl,kfl,r+sumf_{l,k}\to f_{l,r}+sum

    #include<bits/stdc++.h>
    #define int unsigned long long
    #define rep(i,l,r) for(int i=l;i<=r;++i)
    #define per(i,r,l) for(int i=r;i>=l;--i)
    using namespace std;
    const int N=2510,base=131;
    int f[N][N];
    int n,A,B,C;
    int hs[N],g[N];
    char s[N];
    int calc(int l,int r){
    	return hs[r]-hs[l-1]*g[r-l+1];
    }
    signed main(){
    	cin>>n>>(s+1)>>A>>B>>C;
    	memset(f,0x3f,sizeof f);
    	g[0]=1;
    	rep(i,1,n) hs[i]=hs[i-1]*base+s[i],g[i]=g[i-1]*base,f[i][i]=A;
    	rep(len,1,n){
    		for(int l=1,r=l+len-1;r<=n;++l,++r){
    			if(len>1){
    				f[l][r]=min({f[l][r],f[l+1][r]+A,f[l][r-1]+A});
    			}
    			int h=calc(l,r),sum=B;
    			rep(k,l,n-len+1){
    				if(calc(k,k+len-1)==h){
    					k+=len-1;
    					sum+=C;
    					f[l][k]=min(f[l][k],f[l][r]+sum);
    				}else{
    					sum+=A;
    				}
    			}
    		}
    	}
    	cout<<f[1][n];
    	return 0;
    }
    
    • 1

    [JOIST 2022] 复制粘贴 3 / Copy and Paste 3

    信息

    ID
    7221
    时间
    3000ms
    内存
    2048MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者