Description

为了提高智商,ZJY去新世界旅游了。可是旅游过后的ZJY杯具的发现要打开通往原来世界的门,必须要解开门上面画的谜题。谜题是这样的:有个\(n\)行\(m\)列的棋盘,棋盘上可以放许多特殊的棋子。每个棋子的攻击范围是\(3\)行,\(p\)列。输入数据用一个\(3\times p\)的矩阵给出了棋子攻击范围的模板,棋子被默认为模板中的第\(1\)行,第\(k\)列,则棋子能攻击到的位置是\(1\),不能攻击到的位置是\(0\)。\(1\leq p\leq m,0\leq k<p\)。输入数据保证第\(1\)行第\(k\)列的位置是\(1\)。打开门的密码就是,在要求棋子互相不能攻击到的前提下,摆放棋子的方案数。注意什么棋子都不摆放也算作一种可行方案。由于方案数可能很大,而密码为\(32\)位的二进制密码,所以ZJY仅需要知道方案数对\(2^{32}\)取余数的结果即可。

Input

输入数据的第一行为两个整数\(n\)和\(m\),表示棋盘的大小。第二行为两个整数\(p\)和\(k\),表示接下来的攻击范围模板的大小,以及棋子在模板中的位置。接下来三行,每行有\(P\)个数,表示攻击范围的模版。每个数字后有一个空格。

Output

输出数据仅有一行,一个整数,表示可行的方案数模\(2^{32}\)的余数。

Range

对于\(10\%\),\(1 \leq n \leq 5,1 \leq m \leq 5\)

对于\(50\%\),\(1 \leq n \leq 1000,1 \leq m \leq 6\)

对于\(100\%\),\(1\leq n\leq 1000000,1\leq m\leq 6\)

Solution

恶心题。

被这题卡了一天。

首先注意到它的行和列是从 \(0\) 开始标号的,所以第 \(1\) 行第 \(p\) 列其实是中间一行的某一列。

预处理出所有能摆放和两行之间能转移的情况。

这里要用位运算,最开始拿数组模拟每位弄了半天还是错的,用位运算一下就出来了。

观察到转移可以用矩阵加速,于是一个矩阵快速幂敲上去就行了。

注意最后求答案矩阵的时候要新开一个数组不能直接在 \(f\) 数组上面求!

Code

  1. #include<cstdio>
  2. #include<cctype>
  3. #include<cstring>
  4. #define int unsigned long long
  5. int maxn;
  6. int mp[5];
  7. int n,m,p,k;
  8. bool vis[105];
  9. int f[70][70];
  10. const int mod=4294967296;
  11. struct Matrix{
  12. int a[100][100];
  13. void clear(){
  14. memset(a,0,sizeof a);
  15. }
  16. void init(){
  17. for(int i=0;i<maxn;i++)
  18. a[i][i]=1;
  19. }
  20. Matrix operator*(const Matrix &x)const{
  21. Matrix z; z.clear();
  22. for(int i=0;i<maxn;i++){
  23. for(int j=0;j<maxn;j++){
  24. for(int k=0;k<maxn;k++){
  25. z.a[i][j]+=(x.a[i][k]*a[k][j])%mod;
  26. z.a[i][j]%=mod;
  27. }
  28. }
  29. }
  30. return z;
  31. }
  32. void print(){
  33. for(int i=0;i<maxn;i++){
  34. for(int j=0;j<maxn;j++)
  35. printf("i=%lld,j=%lld,a=%lld\n",i,j,a[i][j]);
  36. }
  37. puts("");
  38. for(int i=0;i<maxn;i++){
  39. for(int j=0;j<maxn;j++)
  40. printf("%lld",a[i][j]);
  41. puts("");
  42. }
  43. }
  44. }M;
  45. void read(int &x){
  46. x=0; char ch=getchar();
  47. while(!isdigit(ch)) ch=getchar();
  48. while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
  49. }
  50. bool check(int x){
  51. for(int i=1;i<=m;i++){
  52. if(x&(1<<i-1)){
  53. if(p-k+1<=i){
  54. if((x&(mp[2]<<(i+k-p-1)))!=(1ll<<(i-1))){
  55. //printf("x=%lld,i=%lld\n",x,i);
  56. //printf("i-1=%lld,1<<i-1=%lld\n",i-1,1<<i-1);
  57. //printf("i+k-p-1=%lld,mp[2]<<=%lld,x&=%lld,1<<=%lld\n",i+k-p-1,mp[2]<<i+k-p-1,x&(mp[2]<<i+k-p-1),1ll<<(i-1));
  58. return 0;
  59. }
  60. }
  61. else{
  62. if((x&(mp[2]>>(p-k+1-i)))!=(1ll<<i-1))
  63. return 0;
  64. }
  65. }
  66. }
  67. return 1;
  68. }
  69. bool judge(int x,int y){
  70. for(int i=1;i<=m;i++){
  71. if(x&(1<<i-1)){
  72. if(p-k+1<=i){
  73. if((y&(mp[3]<<(i+k-p-1))))
  74. return 0;
  75. }
  76. else{
  77. if((y&(mp[3]>>(p-k+1-i))))
  78. return 0;
  79. }
  80. }
  81. if(y&(1<<i-1)){
  82. if(p-k+1<=i){
  83. if((x&(mp[1]<<(i+k-p-1))))
  84. return 0;
  85. }
  86. else{
  87. if((x&(mp[1]>>(p-k+1-i))))
  88. return 0;
  89. }
  90. }
  91. }
  92. return 1;
  93. }
  94. Matrix ksm(Matrix a,int b,int c){
  95. Matrix ans; ans.init();
  96. while(b){
  97. if(b&1)
  98. ans=ans*a;
  99. a=a*a;
  100. b>>=1;
  101. }
  102. return ans;
  103. }
  104. void mul(int a[70][70],int b[70][70],int c[70][70])
  105. {
  106. int ret[70][70];
  107. memset(ret,0,sizeof ret);
  108. for(int i=0;i<maxn;i++)
  109. for(int k=0;k<maxn;k++)
  110. for(int j=0;j<maxn;j++)
  111. {
  112. ret[i][j]=(ret[i][j]+a[i][k]*b[k][j]%mod)%mod;
  113. }
  114. memcpy(c,ret,sizeof ret);
  115. }
  116. int a[70][70];
  117. int ans[70][70];
  118. void qm(int y)
  119. {
  120. for(int i=0;i<maxn;i++)
  121. ans[i][i]=1;
  122. while(y)
  123. {
  124. if(y&1) mul(ans,a,ans);
  125. mul(a,a,a);
  126. y>>=1;
  127. }
  128. }
  129. signed main(){
  130. read(n),read(m),read(p),read(k); k++;
  131. maxn=1<<m;
  132. for(int i=1;i<=3;i++){
  133. for(int x,j=1;j<=p;j++){
  134. read(x);
  135. if(x)
  136. mp[i]|=1<<p-j;
  137. }
  138. }
  139. Matrix aa; aa.clear();
  140. for(int i=0;i<maxn;i++){
  141. if(check(i)){
  142. vis[i]=1,f[0][i]=1;
  143. //printf("i=%lld\n",i);
  144. }
  145. }
  146. for(int i=0;i<maxn;i++){
  147. for(int j=0;j<maxn;j++){
  148. if(vis[i] and vis[j]){
  149. if(judge(i,j)){
  150. //printf("i=%lld,j=%lld\n",i,j);
  151. aa.a[j][i]=1;
  152. }
  153. }
  154. }
  155. }
  156. /*for(int i=0;i<maxn;i++)
  157. a[0][i]=a[i][0]=1;*/
  158. //aa.print();
  159. Matrix b=ksm(aa,n-1,mod);
  160. int c[70][70]; memset(c,0,sizeof c);
  161. for(int i=0;i<maxn;i++){
  162. for(int j=0;j<maxn;j++){
  163. for(int k=0;k<maxn;k++)
  164. (c[i][j]+=f[i][k]*b.a[k][j])%=mod;
  165. }
  166. }
  167. /*qm(n-1);
  168. mul(f,ans,ans);*/
  169. int sum=0;
  170. for(int i=0;i<maxn;i++){
  171. for(int j=0;j<maxn;j++)
  172. (sum+=c[i][j])%=mod;
  173. }
  174. printf("%llu\n",sum%mod);
  175. return 0;
  176. }

[TJOI2015] 棋盘的更多相关文章

  1. BZOJ 4000: [TJOI2015]棋盘( 状压dp + 矩阵快速幂 )

    状压dp, 然后转移都是一样的, 矩阵乘法+快速幂就行啦. O(logN*2^(3m)) ------------------------------------------------------- ...

  2. 【BZOJ4000】[TJOI2015]棋盘(矩阵快速幂,动态规划)

    [BZOJ4000][TJOI2015]棋盘(矩阵快速幂,动态规划) 题面 BZOJ 洛谷 题解 发现所有的东西都是从\(0\)开始编号的,所以状压只需要压一行就行了. 然后就可以随意矩乘了. #in ...

  3. 【刷题】BZOJ 4000 [TJOI2015]棋盘

    Description Input 输入数据的第一行为两个整数N,M表示棋盘大小.第二行为两个整数P,K, 表示攻击范围模板的大小,以及棋子在模板中的位置.接下来三行, 每行P个数,表示攻击范围的模版 ...

  4. BZOJ4000 [TJOI2015]棋盘

    首先是状态压缩DP... 然后我们发现转移都是一样的...可以矩阵优化... 于是做完啦QAQQQ 题目读不懂?恩多读几遍就读懂了,诶诶诶!别打我呀! /*********************** ...

  5. BZOJ4000 TJOI2015棋盘(状压dp+矩阵快速幂)

    显然每一行棋子的某种放法是否合法只与上一行有关,状压起来即可.然后n稍微有点大,矩阵快速幂即可. #include<iostream> #include<cstdio> #in ...

  6. [BZOJ4000][TJOI2015]棋盘(状压DP+矩阵快速幂)

    题意极其有毒,注意给的行列都是从0开始的. 状压DP,f[i][S]表示第i行状态为S的方案数,枚举上一行的状态转移.$O(n2^{2m})$ 使用矩阵加速,先构造矩阵a[S1][S2]表示上一行为S ...

  7. BZOJ4000 [TJOI2015]棋盘 【状压dp + 矩阵优化】

    题目链接 BZOJ4000 题解 注意题目中的编号均从\(0\)开始= = \(m\)特别小,考虑状压 设\(f[i][s]\)为第\(i\)行为\(s\)的方案数 每个棋子能攻击的只有本行,上一行, ...

  8. TJOI2015 day2解题报告

    TJOI2015终于写完啦~~~ T1:[TJOI2015]旅游 描述:(BZ没题面只能口述了..)一个人在一棵树上走,每次从a->b会进行一次贸易(也就是在这条路径上买入物品然后在后面卖出)然 ...

  9. [暑假的bzoj刷水记录]

    (这篇我就不信有网站来扣) 这个暑假打算刷刷题啥的 但是写博客好累啊  堆一起算了 隔一段更新一下.  7月27号之前刷的的就不写了 , 写的累 代码不贴了,可以找我要啊.. 2017.8.27upd ...

随机推荐

  1. 解决 RabbitMQ 集群 Channel shutdown: connection error 错误(HAProxy 负载均衡)

    相关文章:搭建 RabbitMQ Server 高可用集群 具体错误信息: 2018-05-04 11:21:48.116 ERROR 60848 --- [.168.0.202:8001] o.s. ...

  2. FileReader对象异步获取外部文件的内容

    1.在网页表单中,定义input的type为file,就可以打开存储在计算机上的文件. <!DOCTYPE html> <head> <meta charset=&quo ...

  3. Django和Angular.js模板标签冲突的解决方式

    参考文章:http://yanhua365.lofter.com/post/b417f_1f0361 http://stackoverflow.com/questions/8302928/angula ...

  4. Java 代码重用:操作与上下文重用

    目录 操作重用 参数化操作 上下文重用 上下文作为模板方法 结束语 我几乎不需要讨论为什么重用代码是有利的.代码重用(通常)会导致更快的开发与更少的 BUG.一旦一段代码被封装和重用,那么检查程序是否 ...

  5. Hadoop 实现 TF-IDF 计算

    学习Hadoop 实现TF-IDF 算法,使用的是CDH5.13.1 VM版本,Hadoop用的是2.6.0的jar包,Maven中增加如下即可 <dependency> <grou ...

  6. PHP采用Cookie实现 购物车

    先来看一下逻辑分析图:

  7. Web移动端页面 --响应式和动态REM

    响应式 什么是响应式页面呢? 顾名思义响应式页面就是能做出响应的页面,它的页面效果不是定死的,会随着用户的改变而改变. 如何着手响应式有以下几个思考的方向 找一份设计图 使用Media Query 隐 ...

  8. 登录测试用例sql语句注入

    利用SQL注入漏洞登录后台的实现方法 作者: 字体:[增加 减小] 类型:转载 时间:2012-01-12我要评论 工作需要,得好好补习下关于WEB安全方面的相关知识,故撰此文,权当总结,别无它意.读 ...

  9. WEB自动化(Python+selenium)的API

    在做Web自动化过程中,汇总了Python+selenium的API相关方法,给公司里的同事做了第二次培训,分享给大家                                         ...

  10. 读取本地outlook邮件内容

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...