标签:没有 枚举 out rip std 行操作 for min ns2
给出一种耗时更大的"新颖“做法。
给你一个字符串,可以用题目中给的方式进行合并,问如何合并使得合并后的字符串长度最短。
我们看到了 $ 1<=N<=50 $ ,又注意到题目是对区间进行操作,我们想到了什么?区间DP。
如果学过区间DP,应该知道是小区间合并成大区间。
$ 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个循环) $
$ 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。
#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;
}
标签:没有 枚举 out rip std 行操作 for min ns2
原文地址:https://www.cnblogs.com/huangxuze/p/14717551.html