题目链接

https://agc019.contest.atcoder.jp/tasks/agc019_d

题意简述

有两个0/1串a,ba,b,可以对aa串执行以下操作:

  • 向左旋转aa串,a1,a2, ,ana_1,a_2,\cdots ,a_n变成a2,a3, ,an,a1a_2,a_3,\cdots ,a_n,a_1
  • 向右旋转aa串,a1,a2, ,ana_1,a_2,\cdots ,a_n变成an,a1,a2, ,an1a_n,a_1,a_2,\cdots ,a_{n-1}
  • bi=1b_i=1时反转ii位置,0变1,1变0。

求最少多少次操作后a,ba,b串相同。

题解

枚举aa串向右旋转了多少次,向左旋转同理。显然可以得出旋转后ai̸=bia_i\not =b_i的位置。假设旋转过程中这些位置都没有对上一个bi=1b_i=1的位置,那么要么开始向左旋转一个位置然后转回来,要么转到目标位置后向右旋转一个位置然后转回去。对于每个上述位置,如果开始向左旋转的长度k\leq k时就必须向右旋转,因此可以处理出来然后前缀和一遍求出向左旋转对应需要向右旋转的长度。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return 0;
}

const int maxn=2000;
const int inf=0x3f3f3f3f;

int n,ans,a[maxn+10],b[maxn+10],sum[maxn+10],nxt[maxn+10],past[maxn+10],f[maxn+10];
char tmp[maxn+10];

inline int trans(int i,int x)
{
  if(i+x>n)
    {
      return i+x-n;
    }
  return i+x;
}

inline int getsum(int l,int r)
{
  if(r>=l)
    {
      return sum[r]-sum[l-1];
    }
  return sum[n]-sum[l-1]+sum[r];
}

int solve()
{
  for(int i=1; i<=n; ++i)
    {
      sum[i]=sum[i-1]+b[i];
    }
  for(int i=1; i<=n; ++i)
    {
      for(int j=0; j<n; ++j)
        {
          if(getsum(i,trans(i,j)))
            {
              nxt[i]=j;
              break;
            }
        }
      for(int j=0; j<n; ++j)
        {
          if(getsum(trans(i,n-j),i))
            {
              past[i]=j;
              break;
            }
        }
    }
  for(int i=0; i<n; ++i)
    {
      memset(f,0,sizeof f);
      int cnt=0;
      for(int j=1; j<=n; ++j)
        {
          if(a[j]!=b[trans(j,i)])
            {
              ++cnt;
              if(nxt[j]-i>0)
                {
                  f[past[j]-1]=std::max(f[past[j]-1],nxt[j]-i);
                }
            }
        }
      for(int j=n-1; j>=0; --j)
        {
          f[j]=std::max(f[j],f[j+1]);
          ans=std::min(ans,(f[j]+j)*2+i+cnt);
        }
    }
  return 0;
}

int main()
{
  scanf("%s",tmp+1);
  n=strlen(tmp+1);
  for(int i=1; i<=n; ++i)
    {
      a[i]=tmp[i]-'0';
    }
  scanf("%s",tmp+1);
  for(int i=1; i<=n; ++i)
    {
      b[i]=tmp[i]-'0';
    }
  int flag=0;
  for(int i=1; i<=n; ++i)
    {
      if(b[i])
        {
          flag=1;
          break;
        }
    }
  if(!flag)
    {
      for(int i=1; i<=n; ++i)
        {
          if(a[i])
            {
              flag=1;
              break;
            }
        }
      puts(flag?"-1":"0");
      return 0;
    }
  ans=inf;
  solve();
  std::reverse(a+1,a+n+1);
  std::reverse(b+1,b+n+1);
  solve();
  printf("%d\n",ans);
  return 0;
}