BZOJ.4572.[SCOI2016]围棋(轮廓线DP)
\(Description\)
给定\(n,m,c\)。\(Q\)次询问,每次询问给定\(2*c\)的模板串,求它在多少个\(n*m\)的棋盘中出现过。棋盘的每个格子有三种状态。
\(n\leq 100,m\leq 12,c\leq 6,Q\leq 5\)。
\(Solution\)
模板串只有\(2\)行,把它拆成两个串,考虑轮廓线DP。
对于\((i,j)\)这个格子,只需要考虑\((i-1,j)\)是否匹配了模式串的第一行,\((i,j)\)匹配到模式串第二行的哪。
所以令\(f[i][j][S][x][y]\)表示,当前为\((i,j)\),\(i-1\)行匹配了模式串第一行的位置状态为\(S\)(\(S\)第\(k\)位为\(1\)说明\((i-1,k)\)匹配了第一行),第\(i\)行匹配到模式串第一行的位置\(x\),匹配到第二行\(y\)。
转移时枚举三种字符,用KMP预处理会跳到哪一位。
复杂度\(O(n*m*2^{m-c+1}*c^2)\)(\(S\)只需记\(m-c+1\)位)。
//2392kb 792ms
#include <cstdio>
#include <cstring>
#include <algorithm>
#define mod 1000000007
#define Mod(x) x>=mod&&(x-=mod)
#define Add(x,v) (x+=v)>=mod&&(x-=mod)
typedef long long LL;
const int N=13;
const LL LIM=(LL)1e18;
int f[2][(1<<12)+1][7][7];
struct KMP
{
int s[N],fail[N],to[N][3];
char tmp[N];
void Build(const int n)
{
scanf("%s",tmp+1);
for(int i=1; i<=n; ++i) s[i]=tmp[i]=='W'?0:(tmp[i]=='B'?1:2);
for(int i=2,j=0; i<=n; ++i)
{
while(j && s[i]!=s[j+1]) j=fail[j];
fail[i]=s[i]==s[j+1]?++j:0;
}
s[n+1]=233;
for(int i=0; i<=n; ++i)
for(int c=0; c<3; ++c)
{
int j=i;
while(j && s[j+1]!=c) j=fail[j];
to[i][c]=s[j+1]==c?j+1:0;
}
}
}s1,s2;
inline void Clear(int (*f)[7][7],const int lim,const int C)
{
for(int s=0; s<=lim; ++s)
for(int a=0; a<=C; ++a)
for(int b=0; b<=C; ++b) f[s][a][b]=0;
}
int main()
{
int n,m,C,Q; scanf("%d%d%d%d",&n,&m,&C,&Q);
int lim=(1<<m-C+1)-1; LL pw3=1;
for(int i=n*m; i; --i) pw3=3ll*pw3, pw3>=LIM&&(pw3%=mod);
pw3%=mod;
while(Q--)
{
s1.Build(C), s2.Build(C);
int p=0; memset(f[p],0,sizeof f[p]);
f[p][0][0][0]=1;
for(int i=1; i<=n; ++i)
{
Clear(f[p^1],lim,C);// memset(f[p^1],0,sizeof f[p^1]);//状态少啊
for(int s=0; s<=lim; ++s)
{
LL tmp=0;
for(int a=0; a<=C; ++a)
for(int b=0; b<=C; ++b)
tmp+=f[p][s][a][b];
f[p^1][s][0][0]=tmp%mod;
}
p^=1;
for(int j=1; j<=m; ++j)
{
p^=1, Clear(f[p],lim,C);// memset(f[p],0,sizeof f[p]);
for(int s=0; s<=lim; ++s)
for(int a=0; a<=C; ++a)
for(int b=0,v; b<=C; ++b)
if((v=f[p^1][s][a][b]))
for(int c=0; c<3; ++c)
{
int ta=s1.to[a][c],tb=s2.to[b][c];
if(j<C) Add(f[p][s][ta][tb],v);
else if(!(s>>j-C&1))
if(ta!=C) Add(f[p][s][ta][tb],v);
else Add(f[p][s|(1<<j-C)][ta][tb],v);
else if(tb!=C)
if(ta!=C) Add(f[p][s^(1<<j-C)][ta][tb],v);
else Add(f[p][s][ta][tb],v);
}
}
}
LL ans=0;
for(int s=0; s<=lim; ++s)
for(int a=0; a<=C; ++a)
for(int b=0; b<=C; ++b) ans+=f[p][s][a][b];
printf("%d\n",(int)((pw3+mod-ans%mod)%mod));
}
return 0;
}
BZOJ.4572.[SCOI2016]围棋(轮廓线DP)的更多相关文章
- 4572: [Scoi2016]围棋 轮廓线DP KMP
国际惯例的题面:这种题目显然DP了,看到M这么小显然要状压.然后就是具体怎么DP的问题.首先我们可以暴力状压上一行状态,然后逐行转移.复杂度n*3^m+3^(m*2),显然过不去. 考虑状态的特殊性, ...
- [LOJ#2017][轮廓线DP][KMP]「SCOI2016」围棋
题目传送门 看到 \(m\le 12\) 和 \(c\le 6\) ,容易想到状压 DP 考虑转化成 \(3^{nm}\) 减去不合法的方案数,轮廓线 DP :\(f[i][j][S][k][h]\) ...
- 轮廓线DP POJ3254 && BZOJ 1087
补了一发轮廓线DP,发现完全没有必要从右往左设置状态,自然一点: 5 6 7 8 9 1 2 3 4 如此设置轮廓线标号,转移的时候直接把当前j位改成0或者1就行了.注意多记录些信息对简化代码是很有帮 ...
- 【BZOJ 4572】【SCOI 2016】围棋
http://www.lydsy.com/JudgeOnline/problem.php?id=4572 轮廓线DP:设\(f(i,j,S,x,y)\). \(S\)表示\((i,1)\)到\((i, ...
- BZOJ4572: [Scoi2016]围棋
Description 近日,谷歌研发的围棋AI—AlphaGo以4:1的比分战胜了曾经的世界冠军李世石,这是人工智能领域的又一里程碑. 与传统的搜索式AI不同,AlphaGo使用了最近十分流行的卷积 ...
- [SCOI2016]围棋
Description 近日,谷歌研发的围棋AI-AlphaGo以4:1的比分战胜了曾经的世界冠军李世石,这是人工智能领域的又一里程碑.与传统的搜索式AI不同,AlphaGo使用了最近十分流行的卷积神 ...
- HDU4804 Campus Design 轮廓线dp
跟上面那篇轮廓线dp是一样的,但是多了两个条件,一个是在原图上可能有些点是不能放的(即障碍),所以转移的时候要多一个判断color[i][j]是不是等于1什么的,另外一个是我们可以有多的1*1的骨牌, ...
- POJ2411 Mondriaan's Dream 轮廓线dp
第一道轮廓线dp,因为不会轮廓线dp我们在南京区域赛的时候没有拿到银,可见知识点的欠缺是我薄弱的环节. 题目就是要你用1*2的多米诺骨排填充一个大小n*m(n,m<=11)的棋盘,问填满它有多少 ...
- UVA - 11270 轮廓线DP
其实这题还能用状压DP解决,可是时间达到2000ms只能过掉POJ2411.状压DP解法详见状压DP解POJ2411 贴上POJ2411AC代码 : 2000ms 时间复杂度h*w*(2^w)*(2^ ...
随机推荐
- bzoj3991 lca+dfs序应用+set综合应用
/* 给定一棵树,树上会出现宝物,也会有宝物消失 规定如果要收集树上所有宝物,就要选择一个点开始,到每个宝物点都跑一次,然后再回到那个点 现在给定m次修改,每次修改后树上就有一个宝物消失,或者一个宝物 ...
- 关于springboot整合配置pagehelper插件的方法
一,java代码配置法 这种方法个人感觉比较繁琐不是很推荐,而且也不怎么符合springboot的理念,但是胜在也能够用,所以就列起来,万一以后接手的代码是用这种方式的也方便自己维护. 首先引入jar ...
- 关于 java.lang.ClassCastException: java.math.BigDecimal cannot be cast to java.lang.String
今天遇到了这个异常,其实是自己经验欠缺所致.我是通过mybatis查询到数据库传过来的主键,是一个32位的char类型. 代码: //查询总账表的该组织总账记录,包括该条记录的主键id.账户余额Dzz ...
- Caused by: java.net.ConnectException: Connection refused: master/192.168.3.129:7077
1:启动Spark Shell,spark-shell是Spark自带的交互式Shell程序,方便用户进行交互式编程,用户可以在该命令行下用scala编写spark程序. 启动Spark Shell, ...
- Web.Config引入配置ConfigSource
1.配置文件要和Config文件通一个项目 2.注意路径的写法 3.appSettings和connectionStrings等都可以设置configSource 4.这样发布到不同的环境的时候,改动 ...
- JSP基础知识➣获取参数和过滤器(四)
JSP表单提交和参数获取 JSP表单提交的两种方式:post和get,通过这两种方式提交的参数到后台,获取参数的值主要由request来处理,获取值的方式有以下几种: getParameter(): ...
- C#搭建Oauth2.0认证流程以及代码示例
我认为对于一个普遍问题,必有对应的一个简洁优美的解决方案.当然这也许只是我的一厢情愿,因为根据宇宙法则,所有事物总归趋于混沌,而OAuth协议就是混沌中的产物,不管是1...0a还是2.,单看版本号就 ...
- SQL Server数据库存储过程中拼接字符串注意的问题
在SQL Server数据库中书写复杂的存储过程时,一般的做法是拼接字符串,最后使用EXEC sp_executesql '拼接的字符串' 查询出结果. 先看一段代码: -- ============ ...
- 通过java代码进行impala和kudu的对接
对于impala而言,开发人员是可以通过JDBC连接impala的,有了JDBC,开发人员可以通过impala来间接操作kudu: maven导包: <!-- https://mvnreposi ...
- lvs-ldirectord
Ldirectord;用来对后端服务器的检测状态后并进行操作 安装在director上 对后端的rs服务器的 健康检查包括几方面: 1通过ping 若可以ping到服务器表示主机活着 2 对端口的检 ...