国际惯例的题面:

这种题目显然DP了,看到M这么小显然要状压。
然后就是具体怎么DP的问题。
首先我们可以暴力状压上一行状态,然后逐行转移。复杂度n*3^m+3^(m*2),显然过不去。

考虑状态的特殊性,每个位置是黑子白子我们并不关心,我们只关心与模板的匹配情况。
于是我们可以f(i,S,x,y)表示我们决策到i行j列,S表示上一行哪些位置和这一行哪些位置能与模板第一行完全匹配,x表示当前行与模板第一行匹配长度,y表示当前行与模板第二行匹配长度。
转移的话就枚举当前行下一个位置填什么颜色棋子(或空着)即可,复杂度n*(3^m)m*c*c*(2^m)*3,显然也凉了。
但是,我们发现如果一行能与模板第一行完全匹配,显然这个匹配位置最少在这一行的位置c。这样就能把次数中的m变成m-c+1。
这样仍旧不能AC。因为这只是普通的状压DP,显然有很多无用状态。

轮廓线DP的巧妙之处在于:因为采用了逐格转移,它压缩的状态可以部分是上一行的,部分是这一行的。
于是我们可以f(i,j,S,x,y)表示我们决策到i行j列,S表示上一行>=j的哪些位置和这一行<j的哪些位置能与模板第一行完全匹配,x表示当前行与模板第一行匹配长度,y表示当前行与模板第二行匹配长度。
我们枚举下一个格子填什么颜色的棋子,进行转移即可。复杂度n*m*3(m-c+1)*(c^2)*3。

代码:

 #include<cstdio>
typedef long long int lli;
const int maxs=<<,maxl=;
const int mod=1e9+; char ina[maxl],inb[maxl];
int faila[maxl],failb[maxl],nxta[maxl][],nxtb[maxl][];
int f[][maxs][maxl][maxl];
int n,m,c,q,full,mask,cur;
lli ans; inline lli fastpow(lli base,int tim) {
lli ret = ;
while(tim) {
ret = ( tim & ) ? ret * base % mod : ret;
base = ( tim >>= ) ? base * base % mod : base;
}
return ret;
}
inline char gid(char c) {
return c == 'W' ? : c == 'B' ? : ;
}
inline void kmp(char* s,int* fail,int nxt[maxl][]) {
for(int i=;i<=c;i++) s[i] = gid(s[i]);
fail[] = fail[] = ;
for(int i=,j=;i<=c;i++) {
while( j && s[j+] != s[i] ) j = fail[j];
fail[i] = ( j += ( s[j+] == s[i] ) );
}
for(int i=;i<=c;i++) for(int cur=;cur<;cur++) {
int k = i;
while( k && s[k+] != cur ) k = fail[k];
nxt[i][cur] = ( k += ( s[k+] == cur ) );
}
} inline void reset(int f[maxs][maxl][maxl]) {
for(int i=;i<full;i++) for(int j=;j<=c;j++) for(int k=;k<=c;k++) f[i][j][k] = ;
} int main() {
scanf("%d%d%d%d",&n,&m,&c,&q) , full = << ( m - c + ) , mask = full - ;
while(q--) {
scanf("%s%s",ina+,inb+) , kmp(ina,faila,nxta) , kmp(inb,failb,nxtb) , reset(f[cur=]) , f[cur][][][] = ;
for(int i=;i<=n;i++) {
reset(f[cur^=]);
for(int j=;j<full;j++) for(int pa=;pa<c;pa++) for(int pb=;pb<c;pb++) f[cur][j][][] = ( f[cur][j][][] + f[cur^][j][pa][pb] ) % mod;
for(int j=;j<=m;j++) {
reset(f[cur^=]);
for(int sta=;sta<full;sta++) for(int pa=;pa<c;pa++) for(int pb=;pb<c;pb++) if( f[cur^][sta][pa][pb] )for(int sel=;sel<;sel++) {
int nowa = nxta[pa][sel] , nowb = nxtb[pb][sel] , nowsta = sta;
if( j >= c ) nowsta &= ( mask ^ ( << ( j - c ) ) ); // clear bit j - c .
if( nowa == c ) nowsta ^= << ( j - c ) , nowa = faila[nowa]; // set bit j - c .
if( nowb == c ) {
if( sta & ( << ( j - c ) ) ) continue; // paired .
else nowb = failb[nowb];
}
f[cur][nowsta][nowa][nowb] = ( f[cur][nowsta][nowa][nowb] + f[cur^][sta][pa][pb] ) % mod;
}
}
}
ans = fastpow(,n*m);
for(int sta=;sta<full;sta++) for(int pa=;pa<c;pa++) for(int pb=;pb<c;pb++) ans = ( ans - f[cur][sta][pa][pb] + mod ) % mod;
printf("%lld\n",ans);
}
return ;
}

もうこの手を 離さないから笑い合えるよ
我已不会再放手 所以一起欢笑吧
またこの場所から ふたり歩き出そう この道を
让我们再次从这里出发 踏上这条道路
朝の澄んだ陽射し 夜空に瞬く星
清晨干净的阳光 夜空中闪烁的繁星
たわいもないこと 分け合って感じるぬくもり
不管多琐碎的事 互相分享的温暖
ひとりきりの記憶 思い出してしまうたび
每当我回想起独自一人的记忆
いつも鄰で 撫でてくれてたから 笑えた
你总在我身边 抚摸着我朝我微笑

4572: [Scoi2016]围棋 轮廓线DP KMP的更多相关文章

  1. BZOJ.4572.[SCOI2016]围棋(轮廓线DP)

    BZOJ 洛谷 \(Description\) 给定\(n,m,c\).\(Q\)次询问,每次询问给定\(2*c\)的模板串,求它在多少个\(n*m\)的棋盘中出现过.棋盘的每个格子有三种状态. \( ...

  2. [LOJ#2017][轮廓线DP][KMP]「SCOI2016」围棋

    题目传送门 看到 \(m\le 12\) 和 \(c\le 6\) ,容易想到状压 DP 考虑转化成 \(3^{nm}\) 减去不合法的方案数,轮廓线 DP :\(f[i][j][S][k][h]\) ...

  3. BZOJ4572: [Scoi2016]围棋

    Description 近日,谷歌研发的围棋AI—AlphaGo以4:1的比分战胜了曾经的世界冠军李世石,这是人工智能领域的又一里程碑. 与传统的搜索式AI不同,AlphaGo使用了最近十分流行的卷积 ...

  4. [SCOI2016]围棋

    Description 近日,谷歌研发的围棋AI-AlphaGo以4:1的比分战胜了曾经的世界冠军李世石,这是人工智能领域的又一里程碑.与传统的搜索式AI不同,AlphaGo使用了最近十分流行的卷积神 ...

  5. 轮廓线DP POJ3254 && BZOJ 1087

    补了一发轮廓线DP,发现完全没有必要从右往左设置状态,自然一点: 5 6 7 8 9 1 2 3 4 如此设置轮廓线标号,转移的时候直接把当前j位改成0或者1就行了.注意多记录些信息对简化代码是很有帮 ...

  6. HDU4804 Campus Design 轮廓线dp

    跟上面那篇轮廓线dp是一样的,但是多了两个条件,一个是在原图上可能有些点是不能放的(即障碍),所以转移的时候要多一个判断color[i][j]是不是等于1什么的,另外一个是我们可以有多的1*1的骨牌, ...

  7. POJ2411 Mondriaan's Dream 轮廓线dp

    第一道轮廓线dp,因为不会轮廓线dp我们在南京区域赛的时候没有拿到银,可见知识点的欠缺是我薄弱的环节. 题目就是要你用1*2的多米诺骨排填充一个大小n*m(n,m<=11)的棋盘,问填满它有多少 ...

  8. UVA - 11270 轮廓线DP

    其实这题还能用状压DP解决,可是时间达到2000ms只能过掉POJ2411.状压DP解法详见状压DP解POJ2411 贴上POJ2411AC代码 : 2000ms 时间复杂度h*w*(2^w)*(2^ ...

  9. [UOJ422][集训队作业2018]小Z的礼物——轮廓线DP+min-max容斥

    题目链接: [集训队作业2018]小Z的礼物 题目要求的就是最后一个喜欢的物品的期望得到时间. 根据$min-max$容斥可以知道$E(max(S))=\sum\limits_{T\subseteq ...

随机推荐

  1. Java SSH远程执行Shell命令、shell脚本实现(Ganymed SSH)

    jar包下载地址: http://www.ganymed.ethz.ch/ssh2/ 此源码的好处就是没有依赖很多其他的包,拷贝过来干干净净.具体代码实现可以看下文,或参考官方文档,在下载的压缩包里g ...

  2. CSS高度塌陷问题解决方案

    高度塌陷的存在:原因分析 1 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /& ...

  3. 路由器中继(repeater)模式 和 AP+WDS模式区别?

    理论上的 中继(repeater)模式, 只有连接的最后一个才会有信号发出,中间的连接节点是没有信号发出的. AP+WDS模式:就是每一个路由都有信号发出,可以进行信号的全方位覆盖.

  4. 转载:《理解RESTful架构》 阮一峰

    原文:http://www.ruanyifeng.com/blog/2011/09/restful.html 越来越多的人开始意识到,网站即软件,而且是一种新型的软件. 这种"互联网软件&q ...

  5. Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 inconsistent binding

    1.发生原因  springAOP 里面绑定参数出现错误  核对绑定参数的名称    核对 springAOP的版本 2.aop切面表达式写的有误

  6. javascript 练习题目答案1

    以下是这个教程的答案 https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/00143 ...

  7. XPATH语法(一)

    Xpath简介 XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某部分位置的语言.XPath基于XML的树状结构,有不同类型的节点,包括元素节点,属性节点和文本节点 ...

  8. pytest九:使用自定义标记 mark

    pytest 可以支持自定义标记,自定义标记可以把一个 web 项目划分多个模块,然后指定模块名称执行.app 自动化的时候,如果想android 和 ios 公用一套代码时,也可以使用标记功能,标明 ...

  9. python 全栈开发,Day2(in,while else,格式化输出,逻辑运算符,int与bool转换,编码)

    一.in的使用 in 操作符用于判断关键字是否存在于变量中 a = '男孩wusir' print('男孩' in a) 执行输出: True in是整体匹配,不会拆分匹配. a = '男孩wusir ...

  10. Asp.NetWebForm的控件属性

    一:GridView: 1.绑定ID 的值:DataKeyNames="Id", 2.自动产生列的意思:AutoGenerateColumns 3.如何注册脚本:ClientScr ...