LOJ 2172 「FJOI2016」所有公共子序列问题——序列自动机

题目:https://loj.ac/problem/2172

在两个序列自动机上同时走,这样暴搜。

先走字典序小的字符,一边搜一边输出,就是按字典序排序的。

方案数很多,需要高精度?空间很小,要压位。1e9的20位恰好够。

不开 n*n 的DP数组,给出现的状态分配一个位置,开 3e6 的DP数组,空间就能了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=3015,K=60;
int n,m,c[N][K],d[N][K],lst[K];
char a[N],b[N];
int Id(char ch)
{
  if(ch<='Z')return ch-'A';
  return ch-'a'+26;
}
char Id2(int k)
{
  if(k<26)return k+'A';
  return k-26+'a';
}
namespace S1{
  int ans,top; char s[N];
  void dfs(int p0,int p1)
  {
    printf("%s\n",s+1); ans++;
    for(int i=0;i<52;i++)
      if(c[p0][i]<=n&&d[p1][i]<=m)
    {
      s[++top]=Id2(i);
      dfs(c[p0][i],d[p1][i]);
      s[top]=s[top+1];top--;
    }
  }
  void solve()
  {dfs(0,0); printf("%d\n",ans);}
}
namespace S2{
  const int M=3e6,bs=1e9;
  int tot; int dy[N][N];
  struct Node{
    int a[20];//
    void Inc(int k)
    {
      a[1]+=k;
      for(int i=1;i<=a[0];i++)
    if(a[i]>=bs)a[i]-=bs,a[i+1]++;
      while(a[a[0]+1])a[0]++;
    }
    void Inc(Node k)
    {
      int lm=max(a[0],k.a[0]);
      for(int i=1;i<=lm;i++)
    {
      a[i]+=k.a[i];
      if(a[i]>=bs)a[i+1]+=a[i]/bs,a[i]%=bs;
    }
      while(a[a[0]+1])a[0]++;
    }
    void print()
    {
      printf("%d",a[a[0]]);
      for(int i=a[0]-1;i;i--)
    printf("%09d",a[i]);puts("");
    }
  }dp[M];
  int dfs(int p0,int p1)
  {
    if(dy[p0][p1])return dy[p0][p1];
    int cr=++tot; dy[p0][p1]=cr; dp[cr].Inc(1);
    for(int i=0,x,y;i<52;i++)
      if((x=c[p0][i])<=n&&(y=d[p1][i])<=m)
    {
      int v=dfs(x,y); dp[cr].Inc(dp[v]);
    }
    return cr;
  }
  void solve()
  { int v=dfs(0,0); dp[v].print();}
}
int main()
{
  scanf("%d%d",&n,&m);
  scanf("%s",a+1); scanf("%s",b+1);
  for(int i=0;i<52;i++)lst[i]=n+1;
  for(int i=n;i>=0;i--)
    {
      for(int j=0;j<52;j++)
    c[i][j]=lst[j];
      lst[Id(a[i])]=i;
    }
  for(int i=0;i<52;i++)lst[i]=m+1;
  for(int i=m;i>=0;i--)
    {
      for(int j=0;j<52;j++)
    d[i][j]=lst[j];
      lst[Id(b[i])]=i;
    }
  int op;scanf("%d",&op);
  if(op==1)S1::solve();
  else S2::solve();
  return 0;
}

 

上一篇:单片机(一):基础知识


下一篇:尺缩钟慢之动钟变慢——思想实验推导狭义相对论(七)