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

#include<cstdio>
#include<cctype>
#include<cstring>
#define int unsigned long long int maxn;
int mp[5];
int n,m,p,k;
bool vis[105];
int f[70][70];
const int mod=4294967296; struct Matrix{
int a[100][100]; void clear(){
memset(a,0,sizeof a);
} void init(){
for(int i=0;i<maxn;i++)
a[i][i]=1;
} Matrix operator*(const Matrix &x)const{
Matrix z; z.clear();
for(int i=0;i<maxn;i++){
for(int j=0;j<maxn;j++){
for(int k=0;k<maxn;k++){
z.a[i][j]+=(x.a[i][k]*a[k][j])%mod;
z.a[i][j]%=mod;
}
}
}
return z;
} void print(){
for(int i=0;i<maxn;i++){
for(int j=0;j<maxn;j++)
printf("i=%lld,j=%lld,a=%lld\n",i,j,a[i][j]);
}
puts("");
for(int i=0;i<maxn;i++){
for(int j=0;j<maxn;j++)
printf("%lld",a[i][j]);
puts("");
}
}
}M; void read(int &x){
x=0; char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
} bool check(int x){
for(int i=1;i<=m;i++){
if(x&(1<<i-1)){
if(p-k+1<=i){
if((x&(mp[2]<<(i+k-p-1)))!=(1ll<<(i-1))){
//printf("x=%lld,i=%lld\n",x,i);
//printf("i-1=%lld,1<<i-1=%lld\n",i-1,1<<i-1);
//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));
return 0;
}
}
else{
if((x&(mp[2]>>(p-k+1-i)))!=(1ll<<i-1))
return 0;
}
}
}
return 1;
} bool judge(int x,int y){
for(int i=1;i<=m;i++){
if(x&(1<<i-1)){
if(p-k+1<=i){
if((y&(mp[3]<<(i+k-p-1))))
return 0;
}
else{
if((y&(mp[3]>>(p-k+1-i))))
return 0;
}
}
if(y&(1<<i-1)){
if(p-k+1<=i){
if((x&(mp[1]<<(i+k-p-1))))
return 0;
}
else{
if((x&(mp[1]>>(p-k+1-i))))
return 0;
}
}
}
return 1;
} Matrix ksm(Matrix a,int b,int c){
Matrix ans; ans.init();
while(b){
if(b&1)
ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
} void mul(int a[70][70],int b[70][70],int c[70][70])
{
int ret[70][70];
memset(ret,0,sizeof ret);
for(int i=0;i<maxn;i++)
for(int k=0;k<maxn;k++)
for(int j=0;j<maxn;j++)
{
ret[i][j]=(ret[i][j]+a[i][k]*b[k][j]%mod)%mod;
}
memcpy(c,ret,sizeof ret);
} int a[70][70];
int ans[70][70]; void qm(int y)
{
for(int i=0;i<maxn;i++)
ans[i][i]=1;
while(y)
{
if(y&1) mul(ans,a,ans);
mul(a,a,a);
y>>=1;
}
} signed main(){
read(n),read(m),read(p),read(k); k++;
maxn=1<<m;
for(int i=1;i<=3;i++){
for(int x,j=1;j<=p;j++){
read(x);
if(x)
mp[i]|=1<<p-j;
}
}
Matrix aa; aa.clear();
for(int i=0;i<maxn;i++){
if(check(i)){
vis[i]=1,f[0][i]=1;
//printf("i=%lld\n",i);
}
}
for(int i=0;i<maxn;i++){
for(int j=0;j<maxn;j++){
if(vis[i] and vis[j]){
if(judge(i,j)){
//printf("i=%lld,j=%lld\n",i,j);
aa.a[j][i]=1;
}
}
}
}
/*for(int i=0;i<maxn;i++)
a[0][i]=a[i][0]=1;*/
//aa.print();
Matrix b=ksm(aa,n-1,mod);
int c[70][70]; memset(c,0,sizeof c);
for(int i=0;i<maxn;i++){
for(int j=0;j<maxn;j++){
for(int k=0;k<maxn;k++)
(c[i][j]+=f[i][k]*b.a[k][j])%=mod;
}
}
/*qm(n-1);
mul(f,ans,ans);*/
int sum=0;
for(int i=0;i<maxn;i++){
for(int j=0;j<maxn;j++)
(sum+=c[i][j])%=mod;
}
printf("%llu\n",sum%mod);
return 0;
}

[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. orale中如何获取当前月份?

    就本人所知,在oracle中,有两种方式可以提取系统的当前月份: 1.使用extract 函数,具体用法看SQL语句: select extract(month from sysdate) as &q ...

  2. R实战 第七篇:绘图文本表

    文本表是显示数据的重要图形,一个文本表按照区域划分为:列标题,行标题,数据区,美学特征有:前景样式.背景央视.字体.网格线等. 一,使用ggtexttable绘图文本表 载入ggpubr包,可以使用g ...

  3. Day6_time模块

    TIME模块: print(time.time()) #指的是从1970年到现在的秒数 print(time.strftime('%Y-%m-%d %X'))  #指定特定的格式输出时间 print( ...

  4. 关于运行springboot时报Unregistering JMX-exposed beans on shutdown的解决方案

    其实这个错误并不影响程序的运行,但是对于处女座的同仁来说,看到报错难免不舒服,那么看看解决方法,此错误信息的意思是说:在关机状态下未注册jmx暴露的bean. 解决方案是在入口类上加上  @Enabl ...

  5. Java 8 基础教程 - Predicate

    在Java 8中,Predicate是一个函数式接口,可以被应用于lambda表达式和方法引用.其抽象方法非常简单: /** * Evaluates this predicate on the giv ...

  6. C语言代码

    //计算1/1+1/ (1+2) +1/ (1+2+3) +…+1/(1+2+…n)的值,要求小数点后保留6位,n从键盘输入 #include<stdio.h> main(){ ; ; i ...

  7. 用calc()绘制手机图案解锁的九宫格样式

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Angular4.x通过路由守卫进行路由重定向,实现根据条件跳转到相应的页面

    需求: 最近在做一个网上商城的项目,技术用的是Angular4.x.有一个很常见的需求是:用户在点击"我的"按钮时读取cookie,如果有数据,则跳转到个人信息页面,否则跳转到注册 ...

  9. C#学习笔记 day_two

    C#学习笔记 day two Chapter 2 c#基本概念 2.1编译与运行hello world应用程序 点击f5或者vs2010中的运行图标即可 2.3C#的概念拓展 (1)继承性:一个类含有 ...

  10. Oracle知识梳理(三)操作篇:SQL基础操作汇总

    Oracle知识梳理(三)操作篇:SQL基础操作汇总 一.表操作 1.表的创建(CREATE TABLE): 基本语句格式:       CREATE TABLE  table_name ( col_ ...