码迷,mamicode.com
首页 > 其他好文 > 详细

SCOI2007 压缩题解

时间:2021-04-30 12:01:40      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:没有   枚举   out   rip   std   行操作   for   min   ns2   

Preface

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

Description

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

Method

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

DP sequence

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

DP state transition equation

$ f_{1,1,1}=1 $ $ f_{i,i,0}=1 $

$ f_{lft,rit,0}=\min(f_{lft,i,0}+f_{i+1,rit,0}) (lft<=i<rit) $

$ f_{lft,rit,1}=\min(f_{lft,i,1}+f_{i+1,rit,0}) (lft<=i<rit) $

$ f_{lft,rit,2}=\min(\min(f_{lft,i,1},f_{lft,i,2},f_{lft,i,0})+\min(f_{i+1,rit,1},f_{i+1,rit,0})) (lft<=i<rit) $

$ f_{lft,rit,1}=\min(f_{lft,lft+pw_x-1,1}+x,f_{lft,lft+pw_x-1,0}+x+1) $

$ (pw_x|(rit-lft+1))(lft,rit区间内可以恰好构成pw_x个循环) $

Explanation

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

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

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

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

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

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

$ f_{lft,rit,1}=\min(f_{lft,lft+pw_x-1,1}+x,f_{lft,lft+pw_x-1,0}+x+1) $

$ (pw_x|(rit-lft+1))(lft,rit区间内可以恰好构成pw_x个循环) $ ---这就是题目的条件,也是本题的最难点,我们可以发现,每多一个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;
}

SCOI2007 压缩题解

标签:没有   枚举   out   rip   std   行操作   for   min   ns2   

原文地址:https://www.cnblogs.com/huangxuze/p/14717551.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!