SCOI2016围棋
来源:互联网 发布:怎样做好淘宝才有生意 编辑:程序博客网 时间:2024/04/29 00:00
题目大意
有个n*m的格子图,每个格子上有三种数。
给出q个2*c模版,对于每个模版,求有多少种格子图能够匹配这个模版。
数据范围
q
直观想法
设
转移显然。
然后这样的时间复杂度是
缩减状态
每次计算匹配一个的。
可以发现,由于我们只要匹配一个模版,所以有许多的状态都是无用的,于是我们可以缩减状态。
如何缩减?
对于一个状态,我们关心的只是那个位置匹配了
然后由于前c-1位都不可能为1(因为一个二进制位为1当且仅当以当前位为结尾的c为是与模版是一样的),所以共有
那么转移的东西如图(箭头表示由哪个数组推出哪个数组,可能本人比较蠢,用的数组太多了):
转移就很显然了,额如果不明白,看标称吧^_^
这样的时间复杂度就是
空间复杂度为
然后,如果m-c比较大,它就会GG了
很遗憾,数据中真的有这样的数据。。。。。
庆幸的是,数据中的这个的n是等于2的,n=2又可以怎样做呢,于是他就可以直接dp就好了,设u[i][w0][w1]表示当前做到第i位,匹配到s0的w0,s1的w1,然后转移显然。。。。。
感觉很水的方法啊啊啊啊啊
说一句:有种水法的感觉
贴个代码哈哈哈哈哈哈:
#include<cstring>#include<cstdio>#include<algorithm>#include<cmath>#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long LL;typedef double db;int get(){ char ch; int s=0; bool pd=0; while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-'); if (ch=='-')pd=1; else s=ch-'0'; while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0'; if (pd)return -s; return s;}const int N = 110;const int M = 20;const int mo = 1e+9+7;const int zt = 260;int mi[13],n,m,c,q,len;int t[M][7][7][zt][zt],g[zt][zt],p[zt],v[zt][zt],w[zt],f[N][zt];int u[N][7][7];LL ans;int s[2][M];int next[2][M];LL v3[N*M];int trans(char ch){ switch (ch){ case 'W':return 0; case 'B':return 1; case 'X':return 2; }}void init(int v){ char ch; while(ch=getchar(),ch!='B'&&ch!='W'&&ch!='X'); s[v][1]=trans(ch); fo(i,2,c)s[v][i]=trans(getchar()); int j=0; fo(i,2,c){ while(j&&s[v][j+1]!=s[v][i])j=next[v][j]; if (s[v][j+1]==s[v][i])j++; next[v][i]=j; }}void work0(){ fo(ttt,1,q){ init(0); init(1); fo(i,0,m)fo(w0,0,c)fo(w1,0,c)u[i][w0][w1]=0; u[0][0][0]=1; ans=0; fo(i,0,m-1) fo(w0,0,c-1) fo(w1,0,c-1) if (u[i][w0][w1]){ fo(v0,0,2) fo(v1,0,2){ int _w0=w0,_w1=w1; while(_w0&&s[0][_w0+1]!=v0)_w0=next[0][_w0]; if (s[0][_w0+1]==v0)_w0++; while(_w1&&s[1][_w1+1]!=v1)_w1=next[1][_w1]; if (s[1][_w1+1]==v1)_w1++; if (_w0==c&&_w1==c) ans=(ans+LL(u[i][w0][w1])*v3[2*(m-1-i)]%mo)%mo; else{ if (_w0==c)_w0=next[0][c]; if (_w1==c)_w1=next[1][c]; u[i+1][_w0][_w1]=(u[i+1][_w0][_w1]+u[i][w0][w1])%mo; } } } printf("%lld\n",ans); }}void work1(){ fo(ttt,1,q){ init(0); init(1); fo(i,0,m)fo(w0,0,c)fo(w1,0,c)fo(t0,0,mi[len]-1)fo(t1,0,mi[len]-1) t[i][w0][w1][t0][t1]=0; fo(t0,0,mi[len]-1)fo(t1,0,mi[len]-1)g[t0][t1]=v[t0][t1]=0; fo(t0,0,mi[len]-1)p[t0]=w[t0]=0; fo(i,0,n)fo(t0,0,mi[len]-1)f[i][t0]=0; t[0][0][0][0][0]=1; fo(i,0,m-1) fo(w0,0,c-1) fo(w1,0,c-1) fo(t0,0,mi[len]-1) fo(t1,0,mi[len]-1) if (t[i][w0][w1][t0][t1]){ fo(v,0,2){ int _w0=w0,_w1=w1,_t0=t0,_t1=t1; while(_w0&&s[0][_w0+1]!=v)_w0=next[0][_w0]; if (s[0][_w0+1]==v)_w0++; while(_w1&&s[1][_w1+1]!=v)_w1=next[1][_w1]; if (s[1][_w1+1]==v)_w1++; if (_w0==c){ _w0=next[0][c]; _t0|=mi[i+1-c]; } if (_w1==c){ _w1=next[1][c]; _t1|=mi[i+1-c]; } t[i+1][_w0][_w1][_t0][_t1]=(t[i+1][_w0][_w1][_t0][_t1]+t[i][w0][w1][t0][t1])%mo; } } fo(w0,0,c-1) fo(w1,0,c-1) fo(t0,0,mi[len]-1) fo(t1,0,mi[len]-1){ g[t0][t1]=(g[t0][t1]+t[m][w0][w1][t0][t1])%mo; p[t1]=(p[t1]+t[m][w0][w1][t0][t1])%mo; } fo(t0,0,mi[len]-1) fo(t1,0,mi[len]-1) if ((t1&t0)>0)w[t0]=(w[t0]+p[t1])%mo; else fo(_t0,0,mi[len]-1) v[t0][_t0]=(v[t0][_t0]+g[t1][_t0])%mo; f[0][0]=1; ans=0; fo(i,0,n-1) fo(t0,0,mi[len]-1) if (f[i][t0]){ ans=(ans+LL(f[i][t0])*w[t0]%mo*v3[(n-i-1)*m]%mo)%mo; fo(_t0,0,mi[len]-1) f[i+1][_t0]=(f[i+1][_t0]+LL(f[i][t0])*v[t0][_t0]%mo)%mo; } printf("%lld\n",ans); }}int main(){ n=get();m=get();c=get();q=get(); v3[0]=1; fo(i,1,n*m)v3[i]=v3[i-1]*3%mo; mi[0]=1; fo(i,1,12)mi[i]=mi[i-1]*2; len=m-c+1; if (n==2)work0(); else work1(); return 0;}
0 0
- SCOI2016围棋
- bzoj4572: [Scoi2016]围棋
- 4572: [Scoi2016]围棋
- BZOJ4572: [Scoi2016]围棋
- 围棋
- 围棋
- 围棋
- 围棋
- 围棋
- 围棋
- 围棋
- [SCOI2016]萌萌哒
- [Scoi2016]美味
- SCOI2016 萌萌哒
- 围棋,又见围棋
- 围棋程序=围棋数据结构+围棋算法
- 围棋打谱
- 电脑围棋
- Java设计模式—中介者模式
- 2. mac mysql error
- php对特殊字符的处理
- Opencv图像识别从零到精通(7)----图像平移、旋转、镜像
- css鼠标手型
- SCOI2016围棋
- hdu1048-密码问题 字符串转换
- Fragment的setUserVisibleHint方法实现懒加载
- jQuery之动画效果
- 建立ROS的代码环境
- Codeforces 696A. Lorenzo Von Matterhorn(map离散化)
- HDU 1175 连连看
- Linux进程间通讯(IPC)------FIFO
- Android笔记--整理我所理解的Touch 事件分发机制