蓝书(算法竞赛进阶指南)刷题记录——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
#include
#include
#include
#include
  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;
}

你可能感兴趣的:(蓝书(算法竞赛进阶指南)刷题记录——POJ2176 Folding(区间DP))