「SCOI2016」围棋

打CF后困不拉基的,搞了一上午...

考虑直接状压棋子,然后发现会t

考虑我们需要上一行的状态本质上是某个位置为末尾是否可以匹配第一行的串

于是状态可以\(2^m\)压住了,但还是会T

考虑到复杂度瓶颈在于每行的状态都要枚举上一行的状态,是按行转移的。

那么如果做一个轮廓线,就可以按格子转移

考虑有那些状态,当前格子\(i,j\),当前轮廓线是否可以匹配第一行的串的状态\(s\)

然后你试试发现如果想好好转移

得存一个\((i,j)\)匹配到第一行串的位置\(x\),和第二行串的位置\(y\)

这里的思考方向倾向于先想转移,转移不了再加状态

然后发现这个匹配的过程可以使用KMP优化,转移的均摊是\(O(1)\)的

复杂度\(O(nm2^{m-c+1}c^2)\)

这里复杂度写成\(2^m\)可能不太稳...


Code:

#include <cstdio>
#include <cctype>
#include <cstring>
template <class T>
void read(T &x)
{
x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
const int mod=1e9+7;
void add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
void mul(int &x,int y){x=1ll*x*y%mod;}
int n,m,c,q,dp[2][1<<12][7][7];
int nxt1[12],nxt2[12],d1[12],d2[12];
char s1[12],s2[12];
void init(char *s,int *d,int *nxt)
{
for(int i=1;i<=c;i++) d[i]=(s[i]=='W'?2:(s[i]=='B'));
for(int j=0,i=2;i<=c;i++)
{
while(j&&d[j+1]!=d[i]) j=nxt[j];
if(d[j+1]==d[i]) ++j;
nxt[i]=j;
}
}
int get(int *nxt,int p,int col,int *d)
{
while(p&&d[p+1]!=col) p=nxt[p];
if(d[p+1]==col) ++p;
return p;
}
int main()
{
read(n),read(m),read(c),read(q);
while(q--)
{
memset(d1,-1,sizeof d1),memset(nxt1,0,sizeof nxt1);
memset(d2,-1,sizeof d2),memset(nxt2,0,sizeof nxt2);
scanf("%s",s1+1),init(s1,d1,nxt1);
scanf("%s",s2+1),init(s2,d2,nxt2);
memset(dp,0,sizeof dp);
int sum=1,cur=0,tx,ty,t,l=m-c+1;
dp[cur][0][0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<m;j++)
{
memset(dp[cur^1],0,sizeof dp[cur^1]);
for(int s=0;s<1<<l;s++)
for(int x=0;x<=c;x++)
for(int y=0;y<=c;y++)
if(dp[cur][s][x][y])
for(int col=0;col<3;col++)
{
tx=get(nxt1,x,col,d1);
ty=get(nxt2,y,col,d2);
if(j+1>=c)
{
t=s&(~(1<<j+1-c));
t|=(tx==c)<<j+1-c;
}
else t=s;
if(j+1>=c&&(s>>j+1-c&1)&&ty==c) continue;
add(dp[cur^1][t][tx][ty],dp[cur][s][x][y]);
}
cur^=1;
mul(sum,3);
}
for(int s=0;s<1<<l;s++)
for(int x=0;x<=c;x++)
for(int y=0;y<=c;y++)
if(x||y)
add(dp[cur][s][0][0],dp[cur][s][x][y]),dp[cur][s][x][y]=0;
}
int ans=0;
for(int s=0;s<1<<l;s++)
add(ans,dp[cur][s][0][0]);
add(sum,mod-ans);
printf("%d\n",sum);
}
return 0;
}

2019.3.6

「SCOI2016」围棋 解题报告的更多相关文章

  1. 「SCOI2016」妖怪 解题报告

    「SCOI2016」妖怪 玄妙...盲猜一个结论,然后过了,事后一证,然后假了,数据真水 首先要最小化 \[ \max_{i=1}^n (1+k)x_i+(1+\frac{1}{k})y_i \] \ ...

  2. 「SCOI2016」美味 解题报告

    「SCOI2016」美味 状态极差无比,一个锤子题目而已 考虑每次对\(b\)和\(d\)求\(c=d \ xor \ (a+b)\)的最大值,因为异或每一位是独立的,所以我们可以尝试按位贪心. 如果 ...

  3. 「SCOI2016」萌萌哒 解题报告

    「SCOI2016」萌萌哒 这思路厉害啊.. 容易发现有个暴力是并查集 然后我想了半天线段树优化无果 然后正解是倍增优化并查集 有这个思路就简单了,就是开一个并查集代表每个开头\(i\)每个长\(2^ ...

  4. 「ZJOI2016」旅行者 解题报告

    「ZJOI2016」旅行者 对网格图进行分治. 每次从中间选一列,然后枚举每个这一列的格子作为起点跑最短路,进入子矩形时把询问划分一下,有点类似整体二分 至于复杂度么,我不会阿 Code: #incl ...

  5. 「HNOI2016」树 解题报告

    「HNOI2016」树 事毒瘤题... 我一开始以为每次把大树的子树再接给大树,然后死活不知道咋做,心想怕不是个神仙题哦 然后看题解后才发现是把模板树的子树给大树,虽然思维上难度没啥了,但是还是很难写 ...

  6. 「HNOI2016」序列 解题报告

    「HNOI2016」序列 有一些高妙的做法,懒得看 考虑莫队,考虑莫队咋移动区间 然后你在区间内部找一个最小值的位置,假设现在从右边加 最小值左边区间显然可以\(O(1)\),最小值右边的区间是断掉的 ...

  7. 「HNOI2016」网络 解题报告

    「HNOI2016」网络 我有一个绝妙的可持久化树套树思路,可惜的是,它的空间是\(n\log^2 n\)的... 注意到对一个询问,我们可以二分答案 然后统计经过这个点大于当前答案的路径条数,如果这 ...

  8. 「HAOI2018」染色 解题报告

    「HAOI2018」染色 是个套路题.. 考虑容斥 则恰好为\(k\)个颜色恰好为\(c\)次的贡献为 \[ \binom{m}{k}\sum_{i\ge k}(-1)^{i-k}\binom{m-k ...

  9. 「HNOI2016」最小公倍数 解题报告

    「HNOI2016」最小公倍数 考虑暴力,对每个询问,处理出\(\le a,\le b\)的与询问点在一起的联通块,然后判断是否是一个联通块,且联通块\(a,b\)最大值是否满足要求. 然后很显然需要 ...

随机推荐

  1. html总结:背景图片拉伸

    两种方法: ⑴推荐方法 <style>body {background-image:url(images/backimage.jpg);background-size:cover;}< ...

  2. 解决jenkins运行磁盘满的问题

    解决jenkins运行磁盘满的问题 - ling811的专栏 - CSDN博客 https://blog.csdn.net/ling811/article/details/74991899 1.自动丢 ...

  3. Python3练习题 026:求100以内的素数

    p = [i for i in range(2,100)] #建立2-99的列表 for i in range(3,100): #1和2都不用判断,从3开始     for j in range(2, ...

  4. ascii、unicode、utf-8、gbk 区别

    原文:https://blog.csdn.net/u010262331/article/details/46013905 ASCII:遇上0×10, 终端就换行: 遇上0×07, 终端就向人们嘟嘟叫: ...

  5. [转帖]system()、exec()、fork()三个与进程有关的函数的比较

    system().exec().fork()三个与进程有关的函数的比较 https://www.cnblogs.com/qingergege/p/6601807.html 启动新进程(system函数 ...

  6. Centos rpm包安装PHP所需包

    yum -y install php php-devel php-fpm php-xml php-pdo php-ldap php-mysql

  7. lombok 使用 Idea

    Lombok 是一种 Java™ 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO).它通过注解实现这一目的.import lombok.Getter;i ...

  8. Python:matplotlib绘制直方图

    使用hist方法来绘制直方图:     绘制直方图,最主要的是一个数据集data和需要划分的区间数量bins,另外你也可以设置一些颜色.类型参数: plt.hist(np.random.randn(1 ...

  9. 莫烦theano学习自修第十天【保存神经网络及加载神经网络】

    1. 为何保存神经网络 保存神经网络指的是保存神经网络的权重W及偏置b,权重W,和偏置b本身是一个列表,将这两个列表的值写到列表或者字典的数据结构中,使用pickle的数据结构将列表或者字典写入到文件 ...

  10. python 三目运算符

    格式: true_res if condition else false_res Meto 1: Meto 2: >>> x = 2 >>> x+1 if x!=1 ...