【dp】codeforces 83E

简单dp

定义了一个函数f。f(‘’)=’’,设s为一个字符串数组,则f(s[1],s[2])=s’(为一个字符串),s’必须满足s[1]是他的前缀,而s[2]是他的后缀,并且s’的长度必须最短。

F(s[1],s[2],s[3],s[4]…,s[n])=f(f(s[1],s[2],s[3],s[4]…,s[n-1]),s[n])

现在有一个长度为n的字符串序列s,s序列的大小不超过200000,每一个字符串的长度不超过20,而且长度都一样,且均为0\1串。

必须找出两个没有重复元素的子序列a和b,使得序列s的每一个元素都属于其中某一个子序列,并且使得f(a)+f(b)的总长度最小。

很直观的想法是记f[i][j]为到第i个字符串,另一子序列最后一个是第j个字符串的最小值,很直观地可以得到一个方程,但是显然的,光是状态就达到了n^2的级别,因此必须转换思路,观察方程,其实我们多记录了一件事,那就是j+1~i都属于i这个序列,考虑一下我们只将f[i]设为第i个字符串和第i+1个字符串不属于同一个序列,则将转移变为o(n)虽然时间复杂度没变,但是前一个方程时间复杂度已经是下界(状态数),而现在的方程则可以在转移上做手脚,观察方程

F[i]=min{f[j]+s[j+1][i]+w[j][i+1]};s表示区间的函数值,wij表示第i个和第j个的花费,很明显s可以用前缀和拆开,关键在于w这个玩意儿没法用数据结构优化,因为每一个不同的j他的w都会不同,但是w有一个局限就是取值不超过len,我们将一个字符串的f值储存为len个w的值也就确定了,时间复杂度o(n*len)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
const int oo=1073741819;
using namespace std;
int f[2000000],g[21][1048577],n,len,a[2000000],s[2000000],c[2000000],ans;
char ch[300000][21];
int check(int x,int y)
{
  int ne,na,j,k=len;
  for (ne=x&1,na=(y>>(len-1))&1,x>>=1,j=1;j<=len;ne=ne | ((x&1)<<j),na=(na<<1)+((y>>(len-j-1))&1),j++,x>>=1)
    if (ne==na) k=min(k,len-j);
  return k;
}
void init()
{
  int sum,cos,i,ne,j,little;
  scanf("%d\n",&n);
  for (i=1;i<=n;i++) scanf("%s\n",ch[i]+1);
  len=strlen(ch[1]+1);
  for (i=1;i<=n;i++) {
    ne=0;
    for (j=1;j<=len;j++) ne=(ne<<1)+(ch[i][j]-'0');
    c[i]=ne;
  }
  c[0]=0;
  for (i=1;i<=n;i++) a[i]=check(c[i-1],c[i]);
  a[1]=len;
  for (i=1;i<=n;i++) s[i]=s[i-1]+a[i];
  memset(g,61,sizeof(g));
  little=len;
  for (i=1;i<=n-1;i++) {
    sum=little;
    for (ne=c[i+1],j=len;j;j--,ne>>=1) {
      cos=g[j][ne]+(len-j);
      if (cos<sum) sum=cos;
    }
    f[i]=sum+s[i];
    for (cos=c[i]>>1,ne=c[i]&1,j=1;j<=len;j++,ne=ne | ((cos&1)<<(j-1)),cos>>=1) 
      if (f[i]-s[i+1]<g[j][ne]) g[j][ne]=f[i]-s[i+1];
    if (f[i]-s[i+1]+len<little) little=f[i]-s[i+1]+len;
  }
  ans=s[n];
  for (i=1;i<=n-1;i++)
    ans=min(ans,f[i]+s[n]-s[i+1]);
  printf("%d\n",ans);
//  for (i=1;i<=n;i++) printf("%d ",a[i]);
}
int main()
{
  freopen("83E.in","r",stdin);
  freopen("83E.out","w",stdout);
  init();
  return 0;
}




你可能感兴趣的:(【dp】codeforces 83E)