顶好的一道题。其实,是POJ 2411的升级版。但POJ 2411我用的插头DP来做,一时没想到那道题怎么用状态DP,于是回头看POJ 2411那一道的状态DP,其实也很简单,就是每一行都设一个状态,用位来表示,如果上一行为0,则当前行必定是要竖着放的。填1.否则,当前行的位置可以横放填两个格子为1,也可以不放,为0.于是,看上一行的状态能转移到哪些状态,就可以了。

这一道也是一样的想做法,DFS看开始时有哪些状态,记在一个一维矩阵里。因为有一些状态最开始是达不到的,如奇数个1,或者一些不连续1的状态。然后求转移矩阵(这个地方想了很久才想到,因为要做很多重复的工作,所以想到用矩阵)。求矩阵时,也用DFS就可以了。

此处在矩阵相乘时有一个小优化,因为转移矩阵中含0较多,所以把中间变量K提到第一个循环。当含有0时就终止。因为这个地方由TLE,优化到了8000MS,也是满足了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define LL __int64
#define mod 1000000007
using namespace std; struct Matrix{
LL ans[130][130];
};
Matrix pp[31]; LL bgn[130];
LL res[130];
int only;
int number[260];
Matrix transfer;
Matrix per;
bool ok(int s){
int c=0;
for(int i=0;i<8;i++)
if(s&(1<<i)) c++;
if(c%2==0) return true;
return false;
} Matrix operator *(Matrix a,Matrix b){
Matrix c;
for(int i=0;i<only;i++)
for(int j=0;j<only;j++)
c.ans[i][j]=0;
for(int k=0;k<only;k++) //把k提到这里来就过了。。。哈哈,这也是一种优化啊,因为矩阵中0较多,避免了不必要的计算。
for(int i=0;i<only;i++){
if(a.ans[i][k]==0) continue;
for(int j=0;j<only;j++){
c.ans[i][j]=(c.ans[i][j]+(a.ans[i][k]*b.ans[k][j])%mod)%mod;
}
}
return c;
} void find_bgn(int state,int pos){
if(pos>=8) {
bgn[number[state]]++;
return ;
}
int tmp=state;
int i=pos;
if((state&(1<<i))==0&&(state&(1<<((i+1)%8)))==0){
tmp=state|(1<<i)|(1<<((i+1)%8));
find_bgn(tmp,i+2);
}
find_bgn(state,i+1);
} void dfs(int pre,int state,int pos){
if(pos>=8) {
transfer.ans[number[pre]][number[state]]++;
return ;
}
int tmp=state;
int i=pos;
if((state&(1<<i))==0&&(state&(1<<((i+1)%8)))==0){
tmp=state|(1<<i)|(1<<((i+1)%8));
dfs(pre,tmp,i+2);
}
dfs(pre,state,i+1);
} /*
LL can(int a,int b)
{
int st,i,j;
bool end=false;
if(a==0)return b==255? 1LL:0;
for(i=0;i<8;i++)
{
j=(i+7)%8;
if((a&(1<<i))&&(a&(1<<j))==0)
{
st=i;
break;
}
}
for(i=st;i!=st||end==false;i=(i+1)%8)
{
end=true;
j=(i+1)%8;
if(0==(a&(1<<i)))
{
if(0==(b&(1<<i)))return 0;
}
else
{
if((a&(1<<j))&&(b&(1<<i))&&(b&(1<<j)))i++;
else if((b&(1<<i))==0)continue;
else return 0;
}
}
return 1LL;
}
*/
void initial(){
only=0;
memset(number,-1,sizeof(number));
memset(transfer.ans,0,sizeof(transfer.ans));
for(int i=0;i<(1<<8);i++)
if(ok(i)) number[i]=only++; for(int i=0;i<only;i++)
for(int j=0;j<only;j++)
if(i==j) per.ans[i][i]=1;
else per.ans[i][j]=0; memset(bgn,0,sizeof(bgn));
find_bgn(0,0); for(int i=0;i<(1<<8);i++){
if(number[i]!=-1){
dfs(i,255-i,0);
}
}
/*
for(int i=0;i<1<<8;i++)
for(int j=i+1;j<1<<8;j++)
if(number[i]!=-1&&number[j]!=-1)
transfer.ans[number[j]][number[i]]=transfer.ans[number[i]][number[j]]=can(i,j);
transfer.ans[only-1][only-1]=2;
*/
for(int i=1;i<31;i++){
if(i==1)
pp[i]=transfer;
else
pp[i]=pp[i-1]*pp[i-1];
}
} LL pow(int k){
Matrix ans=per,ats=transfer;
int c=1;
while(k){
if(k&1) ans=ans*pp[c];
k>>=1;
c++;
}
LL tmp=0;
for(int j=0;j<only;j++)
tmp=(tmp+(bgn[j]*ans.ans[j][only-1])%mod)%mod;
return tmp;
} int main(){
initial();
int n,T,kase=0;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
LL resul=pow(n-1);
printf("Case %d: %I64d\n",++kase,resul);
}
return 0;
}

  

HDU 4332 Contest 4的更多相关文章

  1. HDU 5045 Contest(状压DP)

    Problem Description In the ACM International Collegiate Programming Contest, each team consist of th ...

  2. hdu - 5045 - Contest(国家压缩dp)

    意甲冠军:N个人M通过主打歌有自己的期望,每个问题发送人玩.它不能超过随机播放的次数1,追求最大业绩预期 (1 ≤ N ≤ 10,1 ≤ M ≤ 1000). 主题链接:pid=5045" ...

  3. [ACM] hdu 5045 Contest (减少国家Dp)

    Contest Problem Description In the ACM International Collegiate Programming Contest, each team consi ...

  4. HDU–5988-Coding Contest(最小费用最大流变形)

    Coding Contest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  5. hdu 5045 Contest(状态压缩DP)

    题解:我们使用一个二位数组dp[i][j]记录进行到第i个任务时,人组合为j时的最大和(这里的j我们用二进制的每位相应一个人). 详细见代码: #include <iostream> #i ...

  6. HDU 5045 Contest

    pid=5045">主题链接~~> 做题感悟:比赛时这题后来才写的,有点小尴尬.两个人商议着写写了非常久才写出来,I want to Powerful ,I believe me ...

  7. HDU 4335 Contest 4

    利用降幂公式..呃,还是自己去搜题解吧.知道降幂公式后,就不难了. #include <iostream> #include <cstdio> #include <alg ...

  8. HDU 4339 Contest 4

    树状数组,主要是抓住要求连续1的个数.这样,初始时,相同的加1,不同的加0. 查询时,用二分搜索右边界.就是比较当前mid-l+1的值与他们之间1的个数(这可以通过树状数组求区间和得出),记录右边界即 ...

  9. HDU 4334 Contest 4

    本来以为是一道水题,好吧,做了才知道,出题的人有多牛.二分搜索是不可能的了,因为会超内存... 看到别人的搜索两个集合的提示,我就自己一边去想了.终于想出来了: 可以这样做,先把每两个集合的和值枚举出 ...

随机推荐

  1. 数据库-mongodb-索引

    1.索引提高查询速度,降低写入速度,权衡常用的查询字段,不必在太多列上建立索引 2.在mongodb中,索引可以按字段升序.降序来创建,便于排序 3.默认是使用btree 来组织索引文件,2.4版以后 ...

  2. 线程基础:JDK1.5+(8)——线程新特性(上)

    1.概要 假设您阅读JAVA的源码.出现最多的代码作者包含:Doug Lea.Mark Reinhold.Josh Bloch.Arthur van Hoff.Neal Gafter.Pavani D ...

  3. XML系统学习

    参考:W3School XML基本概念 1.XML是eXtensible Markup Language,使用DTD(Document Type Definition)来描述数据,主要是为传输和存储数 ...

  4. 自己定义button

    我们应该建立自己的代码库,建立自己的工厂 苹果公司给我们提供了强大的利器 可是我们不应该以简简单单的实现基本功能就满足了 大牛的成长之路.都是自己慢慢深入研究 我们要有成长为大牛的目标 今天给大家写个 ...

  5. LightOJ--1094-- Farthest Nodes in a Tree(树的直径裸题)

    Farthest Nodes in a Tree Time Limit: 2000MS Memory Limit: 32768KB 64bit IO Format: %lld & %llu S ...

  6. myeclipse打开jsp页面慢或者卡死

    不知道你们有没有这种经历,反正无论是公司电脑还是自己电脑,myeclipse打开jsp页面卡的不行不行的,又是甚至会出现卡死的现象,几经周折,找到了解决办法,亲测有效 打开window-prefere ...

  7. PHP 环境搭建工具

    PHP环境搭建工具 一键集成工具 直接安装后部署到相关目录即可浏览 phpStudy 下载地址:https://pan.baidu.com/s/1i6C3Ph7

  8. Oracle学习系类篇(二)

    1.Oracle对表的增删改 1.1添加列 1.2修改列 1.3 删除列 1.4 修改表名称 1.5 修改列名称 1.6 删除主键约束 1.7 添加主键约束 1.8 添加外键约束

  9. LIst和map的遍历

    1. public static void main(String[] args) { // ArrayList类实现一个可增长的动态数组 List<String> list = new ...

  10. php 生成不重复的随机字符串

    md5(uniqid(md5(microtime(true)),true))