题目描述

小豆参加了\(NOI\)的游园会,会场上每完成一个项目就会获得一个奖章,奖章 只会是\(N\), \(O\), \(I\)的字样。在会场上他收集到了\(K\)个奖章组成的串。

兑奖规则是奖章串和兑奖串的最长公共子序列长度为小豆最后奖励的等级。

现在已知兑奖串长度为\(N\),并且在兑奖串上不会出现连续三个奖章为\(NOI\),即奖章中不会出现子串\(NOI\)。

现在小豆想知道各个奖励等级会对应多少个不同的合法兑奖串。

题解

我们可以先考忽略那些奇奇怪怪的限制条件,直接考虑如何统计序列数。

我们先考虑\(LCS\)的dp方法。
\[ dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]+(s[i]==t[j])) \]
我们如果把第二维单独拿出来考虑,我们可以发现第二维是一个单调不降的数列而且前后两项的差是小于等于1的。

因为第二维的长度非常小,所以我们可以把第二维差分之后状压起来作为我们的状态。

而且有一个好处,我们知道了这个状态,就能发当前\(dp\)值还原出来,假设我们知道了下一个字符时什么,我们就可以知道转移后的状态是什么了。

所以我们预处理\(g[i][j]\)表示当前状态为\(i\),新加入字符为\(j\),能够转移的状态。

然后我们再设\(dp[i][j][k]\)表示做到第\(i\)为,当前状态为\(j\),匹配到k个字符(这个是判断那个特殊限制用的),随便转移一下就好了。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int mod=1e9+7;
int tran[200],g[3][1<<16],dp[2][1<<16][3],n,k,nw[20],a[20],ma,ans[20];
char s[20];
inline int rd(){int x=0;char c=getchar();bool f=0;while(!isdigit(c)){if(c=='-')f=1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}return f?-x:x;
}
inline void MOD(int &x){x=x>=mod?x-mod:x;}
int main(){n=rd();k=rd();tran['N']=0;tran['O']=1;tran['I']=2;scanf("%s",s+1);for(int i=1;i<=k;++i)a[i]=tran[(int)s[i]];ma=(1<<k+1);for(int o=0;o<3;++o){for(int i=0;i<ma;++i){for(int j=0;j<=k;++j){nw[j]=(i&(1<<j))!=0;if(j)nw[j]+=nw[j-1]; }for(int j=k;j>=1;--j){nw[j]=max(nw[j],nw[j-1]);if(a[j]==o)nw[j]=max(nw[j],nw[j-1]+1);}for(int j=1;j<=k;++j)nw[j]=max(nw[j],nw[j-1]);int s=0;for(int j=k;j>=1;--j)nw[j]=nw[j]-nw[j-1];for(int j=0;j<=k;++j)s|=(1<<j)*nw[j];g[o][i]=s;}}int now=1,pre=0;dp[now][0][0]=1;for(int i=0;i<n;++i){swap(now,pre);memset(dp[now],0,sizeof(dp[now]));for(int j=0;j<ma;++j)for(int l=0;l<3;++l)if(dp[pre][j][l])for(int p=0;p<3;++p){int no=(p==l)?l+1:(p==0); if(no==3)continue;MOD(dp[now][g[p][j]][no]+=dp[pre][j][l]);}}for(int i=0;i<ma;++i){for(int j=0;j<=k;++j){nw[j]=(i&(1<<j))!=0;if(j)nw[j]+=nw[j-1];}   MOD(ans[nw[k]]+=(1ll*dp[now][i][0]+dp[now][i][1]+dp[now][i][2])%mod);} for(int i=0;i<=k;++i)printf("%d\n",ans[i]);return 0;
}

转载于:https://www.cnblogs.com/ZH-comld/p/10554475.html

TJOI2018Party相关推荐

最新文章

  1. 第十六届全国大学生智能车提问与回复 |7月10日
  2. linux内核二当家,Linux PWN从入门到熟练(二)
  3. 一个项目中既有移动端,同时也有PC端的代码,并且 他们的代码分开写的,那么如何实现在手机跳转手机页面,pc点击跳转pc页面...
  4. BugKuCTF WEB 你必须让他停下
  5. Ubuntu系统---NVIDIA 驱动安装
  6. idea中的markdown文档如何插入图片
  7. 微信公众号开发笔记1-获取Access Token
  8. 前端学习(2982):一文理解undefine
  9. bootstrap 解决弹出窗口(modal) 常见问题
  10. linux-shell面试题
  11. scala implicit隐式转化与隐式参数
  12. 关于阻抗设计的建议-来至深南电路板厂的心水总结
  13. Untracked Files Prevent Checkout (AndroidStudio切换分支报错)
  14. ciscotftp服务器(ciscotftp服务器下载)
  15. Pygame 打字游戏项目
  16. Ian Goodfellow回忆GAN诞生故事:几杯啤酒喝出“20年来最酷的深度学习想法”
  17. Scratch软件编程等级考试三级——20191221
  18. phobos 2.015
  19. matlab设计激光腔,激光原理课程设计--平行平面腔自再现模Fox-Li数值迭代解法及MATLAB实现...
  20. lammps固定原子方法2

热门文章

  1. jenkins配置工程目录-启动case
  2. my.ini优化mysql数据库性能的十个参数(推荐)
  3. 前端笔记----定位
  4. hdu--4028--dp
  5. elupload获取文件名与路径_Uipath获取文件名,路径,扩展名等操作
  6. vector赋值的常见错误
  7. VC的Win32控制台程序中使用MFC库文件
  8. 电池供电的电容麦_太阳能航空障碍灯供电机制设计
  9. 吃鸡服务器不接受响应,绝地求生:蓝洞优化服务器性能,从此告别掉帧延迟!...
  10. GIS实战应用案例100篇(八)-桩号相同,坐标不同,RTK怎么输入曲线要素?