SCOI2007 压缩题解

Preface

给出一种耗时更大的"新颖“做法。

Description

给你一个字符串,可以用题目中给的方式进行合并,问如何合并使得合并后的字符串长度最短。

Method

我们看到了 1<=N<=50 ,又注意到题目是对区间进行操作,我们想到了什么?区间DP。

DP sequence

如果学过区间DP,应该知道是小区间合并成大区间。

DP state transition equation

f1,1,1=1 fi,i,0=1

flft,rit,0=min(flft,i,0+fi+1,rit,0)(lft<=i<rit)

flft,rit,1=min(flft,i,1+fi+1,rit,0)(lft<=i<rit)

flft,rit,2=min(min(flft,i,1,flft,i,2,flft,i,0)+min(fi+1,rit,1,fi+1,rit,0))(lft<=i<rit)

flft,rit,1=min(flft,lft+pwx1,1+x,flft,lft+pwx1,0+x+1)

(pwx|(ritlft+1))(lft,ritpwx)

Explanation

flft,rit,0 ---表示在这一段区间内一个M也没有所能达到的最小字符串长度。

flft,rit,1 ---表示在这一段区间内只有最左边有M所能达到的最小字符串长度。

flft,rit,2 ---表示在这一段区间内除了最左边还有其他地方有M所能达到的最小字符串长度。

flft,rit,0=min(flft,i,0+fi+1,rit,0)(lft<=i<rit) ---一个M也没有只能从其他地方一个M也没有转移过来。

flft,rit,1=min(flft,i,1+fi+1,rit,0)(lft<=i<rit) ---最左边有M必须是左边的区间最左边有M,且右边的区间一个M也没有。

flft,rit,2=min(min(flft,i,1,flft,i,2,flft,i,0)+min(fi+1,rit,1,fi+1,rit,0))(lft<=i<rit) ---除了最左边的其他地方有M,只要强制右区间有M即可达到。

flft,rit,1=min(flft,lft+pwx1,1+x,flft,lft+pwx1,0+x+1)

(pwx|(ritlft+1))(lft,ritpwx) ---这就是题目的条件,也是本题的最难点,我们可以发现,每多一个R,序列长度就会翻倍,那么我们枚举他翻几倍,就是多了几个R,然后在分类讨论,如果前面的区间一个M都没有,那么就需要加一个M,如果前面有M,那么就不需要加M。

Code

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
  int x=0,f=1;char ch=getchar();
  while(!isdigit(ch)&&ch!='-')ch=getchar();
  if(ch=='-')f=-1,ch=getchar();
  while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
  return x*f;
}
/* f[lft][rit][p] [lft,rit] 区间
                  p=0 表示整个区间没有M 
                  p=1 表示只有最左边有M
				  p=2 表示在最左边的其他地方还有M
*/ 
string s;
int ans3,ans4,ans1,ans2,x,y,digit[1000],n,i,j,k,lft,rit,len,f[110][110][3],pw[200],a[1000];
bool check(int l,int r,int len)
{
	int x,i;
	for (i=l;i<=r;i++)
	     {
	     	x=(i-l) % len+l;
	     	if (a[i]!=a[x]) return false;
		 }
	return true;
}
int main()
{
	cin>>s;
	pw[0]=1;
	for (i=1;i<=20;i++) pw[i]=pw[i-1]*2;
	n=s.size();
	for (i=1;i<=100;i++)
	     {
	     	for (j=i;j;j/=10) digit[i]++;
		 }
	for (i=1;i<=n;i++) a[i]=s[i-1]-'a'+1;
	for (i=1;i<=n;i++)
	   for (j=1;j<=n;j++)
	        f[i][j][0]=100000000,f[i][j][2]=100000000,f[i][j][1]=100000000;
	for (i=1;i<=n;i++) 
	     if (i==1) 
		     {
			 f[i][i][0]=1;f[i][i][1]=1;
		     }
	else f[i][i][0]=1;
	for (k=2;k<=n;k++)
	    {
	    	for (lft=1;lft<=n-k+1;lft++)
	    	     {
	    	     	rit=lft+k-1;
	    	     	f[lft][rit][0]=rit-lft+1;
	    	     	for (i=lft;i<rit;i++)
	    	     	     {
						 x=i-lft+1;y=rit-i;
						 ans1=f[lft][i][1];
						 ans2=f[lft][i][0];ans3=f[i+1][rit][1];ans4=f[i+1][rit][0];
						 /*for (j=1;j<=20;j++)
						    if 	(x % pw[j]==0)
						        if (check(lft,i,x/pw[j]))
						            {
						            	len=x/pw[j];
						               	if (lft==1)  
						               	    {
						               	    	ans1=min(ans1,f[lft][lft+len-1][0]+j);
											   }
										else
										    {
										    	ans1=min(ans1,f[lft][lft+len-1][0]+j+1);
										    	ans1=min(ans1,f[lft][lft+len-1][1]+j);
											}
									}
						 for (j=1;j<=20;j++)
						    if 	(y % pw[j]==0)
						        if (check(i+1,rit,y/pw[j]))
						            {
						            	len=y/pw[j];
										ans3=min(ans1,f[i+1][i+1+len-1][0]+j+1);
										ans3=min(ans1,f[i+1][i+1+len-1][1]+j);
									}*/
						 f[lft][rit][0]=min(f[lft][rit][0],ans2+ans4);
						 f[lft][rit][1]=min(f[lft][rit][1],ans1+ans4);
						 f[lft][rit][2]=min(f[lft][rit][2],min(min(ans1,ans2),f[lft][i][2])+min(ans3,f[i+1][rit][2]));
	    	     	     //if ((lft==1)&(rit==5)) cout<<f[lft][rit][1]<<" "<<f[lft][i][1]<<" "<<ans1<<" "<<ans4<<" "<<i<<endl;
						  //f[lft][rit]=min(f[lft][rit],f[lft][i]+f[i+1][rit]);
	    	     	     } 
	    	     	len=rit-lft+1;
	    	     	//cout<<pw[1]<<endl;
	    	     	for (j=1;j<=20;j++)
	    	     	    if (len % pw[j]==0)
	    	     	       if (check(lft,rit,len/pw[j]))
	    	     	           {
	    	     	           f[lft][rit][1]=min(f[lft][rit][1],f[lft][lft+(len/pw[j])-1][1]+j);
	    	     	           f[lft][rit][1]=min(f[lft][rit][1],f[lft][lft+(len/pw[j])-1][0]+j+1);
	    	     	           }
				 }
	     }
  cout<<min(min(f[1][n][1],f[1][n][2]),f[1][n][0])<<endl;
return 0;
}

posted @   OIer_Albedo  阅读(73)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示