蓝书(算法竞赛进阶指南)刷题记录——POJ2176 Folding(区间DP)

题目:POJ2176.
题目大意:给定一个串 s s s,求它压缩后长度最小的串.其中压缩是指把一个串中某些子串压成“出现次数(循环节)”的形式,如串 A B A B A B ABABAB ABABAB可以压成 3 ( A B ) 3(AB) 3(AB).
1 ≤ ∣ S ∣ ≤ 300 1\leq |S|\leq 300 1S300.

WA这怎么可以括号套括号的啊…

容易发现 [ l , r ] [l,r] [l,r]要么通过子区间 [ l , m i d ] [l,mid] [l,mid] [ m i d + 1 , r ] [mid+1,r] [mid+1,r]直接合并而来(不用处理中点旁边两个 l ( s ) l(s) l(s)合并成一个,因为如果这样一定可以通过其它转移转移出来),要么就自我压缩,注意这里的自我压缩是整个串压成一个 l ( s ) l(s) l(s)的形式.

然后记录一下每个区间的最小长度和最小长度的串即可.时间复杂度 O ( n 4 ) O(n^4) O(n4),空间复杂度 O ( n 3 ) O(n^3) O(n3).

不过需要注意一下,最后的答案中是可以出现形如 l ( l ( s ) ) l(l(s)) l(l(s))这种的,例如 2 ( A 3 ( A B C ) ) 2(A3(ABC)) 2(A3(ABC))这种.所以需要注意一下,在压缩的时候拿找到的最小的循环节对应的压缩后最短的串放在括号里.

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=100;

struct state{
  int len;
  char s[N+9];
}dp[N+9][N+9];
char s[N+9],tmp[N+9];
int n;

void Get_state(int L,int R){
  for (int len=1;len<=R-L+1>>1;++len){
    if ((R-L+1)%len) continue;
    bool flag=0;
    for (int i=L+len;i<=R;++i)
      if (s[i]^s[i-len]) {flag=1;break;}
    if (flag) continue;
    int ct=0;
    for (int i=(R-L+1)/len;i;i/=10) tmp[++ct]=i%10+'0';
    for (int i=1;i<=ct>>1;++i) swap(tmp[i],tmp[ct-i+1]);
    tmp[++ct]='(';
    for (int i=1;i<=dp[L][L+len-1].len;++i) tmp[++ct]=dp[L][L+len-1].s[i];
    tmp[++ct]=')';
    dp[L][R].len=ct;
    for (int i=1;i<=ct;++i) dp[L][R].s[i]=tmp[i];
    return;
  }
  for (int i=L;i<=R;++i) dp[L][R].s[++dp[L][R].len]=s[i];
}

Abigail into(){
  scanf("%s",s+1);
  n=strlen(s+1);
}

Abigail work(){
  for (int i=1;i<=n;++i) dp[i][i].s[dp[i][i].len=1]=s[i];
  for (int len=2;len<=n;++len)
    for (int l=1;l+len-1<=n;++l){
      int r=l+len-1;
      Get_state(l,r);
	  for (int mid=l;mid<r;++mid)
	    if (dp[l][mid].len+dp[mid+1][r].len<dp[l][r].len){
		  dp[l][r].len=dp[l][mid].len+dp[mid+1][r].len;
	      for (int i=1;i<=dp[l][mid].len;++i)
	        dp[l][r].s[i]=dp[l][mid].s[i];
	      for (int i=1;i<=dp[mid+1][r].len;++i)
	        dp[l][r].s[i+dp[l][mid].len]=dp[mid+1][r].s[i];
		}
	}
}

Abigail outo(){
  for (int i=1;i<=dp[1][n].len;++i)
    putchar(dp[1][n].s[i]);
  puts("");
}

int main(){
  into();
  work();
  outo();
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值