5336: [TJOI2018]party

题解:

比较水啦。。dp套dp

f[i][j][k]表示枚举了前i位,最大公共子序列匹配状态为j,noi匹配到了第k位

因为g[j]和g[j+1]最多差1 所以可以状压成j

然后内层再dp一下搞出下一个j

于是他的名字就叫做dp套dp了

代码:

 

#include <bits/stdc++.h>
using namespace std;
#define rint register int
#define IL inline
#define rep(i,h,t) for (rint i=h;i<=t;i++)
#define dep(i,t,h) for (rint i=t;i>=h;i--)
#define mid ((h+t)>>1)
#define ll long long
const int mo=1e9+7;
char s[20];
int n,k,f[2][100000][3],c[20],g[20],ans[20];
#define js(x,y) x+y>mo?x=x+y-mo:x=x+y
int qu(int x,int y)
{
  int f[20];
  f[0]=0;
  rep(i,0,k-1)
    if ((x>>i)&1) f[i+1]=f[i]+1;
    else f[i+1]=f[i];
  rep(i,1,k)
  {
    g[i]=max(f[i],g[i-1]);
    g[i]=max(g[i],f[i-1]+(c[i]==y));
  }
  int ans=0;
  rep(i,1,k)
    if (g[i]>g[i-1])
      ans+=1<<(i-1);
  return(ans);
}
int pp(int x)
{
  int cnt=0;
  while (x)
  { 
    if (x&1) cnt++;
    x/=2;
  }
  return cnt;
}
int main()
{
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  ios::sync_with_stdio(false);
  cin>>n>>k;
  cin>>s;
  rep(i,1,k)
    if (s[i-1]=='N') c[i]=1; else
    if (s[i-1]=='O') c[i]=2;
    else c[i]=3; 
  f[0][0][0]=1;
  rep(i,1,n)
  {
    rint now=i%2,lst=(i+1)%2;
    memset(f[now],0,sizeof(f[now]));
    rep(i,0,((1<<k)-1))
    {
      if (f[lst][i][0])
      {
        rep(kk,1,3)
        {
          int x1=qu(i,kk),x2=0;
          if (kk==1) x2=1;
          js(f[now][x1][x2],f[lst][i][0]);
        }
      }
      if (f[lst][i][1])
      {
        rep(kk,1,3)
        {
          int x1=qu(i,kk),x2=0;
          if (kk==2) x2=2;
          if (kk==1) x2=1;
          js(f[now][x1][x2],f[lst][i][1]);
        }
      }
      if (f[lst][i][2])
      {
        rep(kk,1,2)
        {
          int x1=qu(i,kk),x2=0;
          if (kk==1) x2=1;
          js(f[now][x1][x2],f[lst][i][2]);
        }
      }
    }
  }
  int kk=n%2;
  rep(i,0,(1<<k)-1)
    rep(j,0,2)
      js(ans[pp(i)],f[kk][i][j]);
  rep(i,0,k)
    cout<<ans[i]<<endl;
  return 0; 
}

 

posted @ 2018-09-19 21:45  尹吴潇  阅读(277)  评论(0编辑  收藏  举报