[ACM]CCF CSP [201409-5]E题 拼图
2017-10-15 19:46
381 查看
思路:简单的插头DP,计算2^m个状态之间的转移,转换成矩阵乘法。
n很大,用快速幂加速下。做了这么多E题,这题应该算是最简单的了。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define MOD 1000000007
#define MM 7
int a[1<<MM][1<<MM];
long long n;
int m;
#define VACANT(S,u) (u>=0 && u<m && ((S&(1<<u))==0))
int SETADD(int S,int u1,int u2=-1){
S|=1<<u1;
if(u2!=-1) S|=1<<u2;
return S;
}
int c[1<<MM][1<<MM];
void mat_mul(int a[][1<<MM],int b[][1<<MM],int sz=1<<m){
memset(c,0,sizeof(c));
for (int i=0;i<sz;i++)
for (int j=0;j<sz;j++)
for (int k=0;k<sz;k++){
c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j])%MOD;
}
for (int i=0;i<sz;i++)
for (int j=0;j<sz;j++)
a[i][j]=c[i][j];
}
void search(int originS,int S1,int S2=0){
//printf("S1=%d,S2=%d\n",S1,S2);
if (S1==(1<<m)-1){
//printf("%d->%d +1\n",originS,S2);
a[originS][S2]++;
return ;
}
for (int i=0;i<m;i++) //找到第一个没被占用的格子,然后继续搜索
if (VACANT(S1,i)){ //格子i没有被占用
//(1) 2 1(down)
if (VACANT(S1,i+1) && VACANT(S2,i+1)){
search(originS,SETADD(S1,i,i+1),SETADD(S2,i+1));
}
//(2) 2 1(up)
if (VACANT(S1,i+1) && VACANT(S2,i))
search(originS,SETADD(S1,i,i+1),SETADD(S2,i));
//(3) 1 2(up)
if (VACANT(S2,i) && VACANT(S2,i-1))
search(originS,SETADD(S1,i),SETADD(S2,i-1,i));
//(4) 1 2(down)
if (VACANT(S2,i) && VACANT(S2,i+1))
search(originS,SETADD(S1,i),SETADD(S2,i,i+1));
break;
}
}
#define FOR0(i,n) for (int i=0;i<n;i++)
int ans[1<<MM][1<<MM];
int main(){
cin>>n>>m;
memset(a,0,sizeof(a));
for (int S=0;S<(1<<m);S++) search(S,S);
int matsz=(1<<m);
FOR0(i,matsz) FOR0(j,matsz) ans[i][j]=(i==j)?1:0;
//矩阵快速幂 ans=a^(n-1)
long long b=n-1;
while (b){
if (b&1) mat_mul(ans,a);
mat_mul(a,a);
b>>=1;
}
printf("%d\n",ans[0][matsz-1]);
return 0;
}
n很大,用快速幂加速下。做了这么多E题,这题应该算是最简单的了。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define MOD 1000000007
#define MM 7
int a[1<<MM][1<<MM];
long long n;
int m;
#define VACANT(S,u) (u>=0 && u<m && ((S&(1<<u))==0))
int SETADD(int S,int u1,int u2=-1){
S|=1<<u1;
if(u2!=-1) S|=1<<u2;
return S;
}
int c[1<<MM][1<<MM];
void mat_mul(int a[][1<<MM],int b[][1<<MM],int sz=1<<m){
memset(c,0,sizeof(c));
for (int i=0;i<sz;i++)
for (int j=0;j<sz;j++)
for (int k=0;k<sz;k++){
c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j])%MOD;
}
for (int i=0;i<sz;i++)
for (int j=0;j<sz;j++)
a[i][j]=c[i][j];
}
void search(int originS,int S1,int S2=0){
//printf("S1=%d,S2=%d\n",S1,S2);
if (S1==(1<<m)-1){
//printf("%d->%d +1\n",originS,S2);
a[originS][S2]++;
return ;
}
for (int i=0;i<m;i++) //找到第一个没被占用的格子,然后继续搜索
if (VACANT(S1,i)){ //格子i没有被占用
//(1) 2 1(down)
if (VACANT(S1,i+1) && VACANT(S2,i+1)){
search(originS,SETADD(S1,i,i+1),SETADD(S2,i+1));
}
//(2) 2 1(up)
if (VACANT(S1,i+1) && VACANT(S2,i))
search(originS,SETADD(S1,i,i+1),SETADD(S2,i));
//(3) 1 2(up)
if (VACANT(S2,i) && VACANT(S2,i-1))
search(originS,SETADD(S1,i),SETADD(S2,i-1,i));
//(4) 1 2(down)
if (VACANT(S2,i) && VACANT(S2,i+1))
search(originS,SETADD(S1,i),SETADD(S2,i,i+1));
break;
}
}
#define FOR0(i,n) for (int i=0;i<n;i++)
int ans[1<<MM][1<<MM];
int main(){
cin>>n>>m;
memset(a,0,sizeof(a));
for (int S=0;S<(1<<m);S++) search(S,S);
int matsz=(1<<m);
FOR0(i,matsz) FOR0(j,matsz) ans[i][j]=(i==j)?1:0;
//矩阵快速幂 ans=a^(n-1)
long long b=n-1;
while (b){
if (b&1) mat_mul(ans,a);
mat_mul(a,a);
b>>=1;
}
printf("%d\n",ans[0][matsz-1]);
return 0;
}
相关文章推荐
- CCFCSP 201409-1相邻数对
- [ACM]CCF CSP [201612-5]E题 卡牌游戏【75分的程序】
- 【CCFCSP】201409-3 字符串匹配
- [ACM]CCF CSP[201703-5]E题 引水入城【60分程序】
- CCF CSP 201409-1 相邻数对
- CCF CSP试题 201409-2 画图
- [ACM]CCF CSP [201709-5]E题 除法
- CCF CSP 201409-2 画图
- [ACM]CCF CSP [201609-5]E题 祭坛
- CCFCSP 201409-2 画图
- CCF CSP 201409-1 相邻数对
- CCF-CSP 201409-4 最优配餐(BFS)
- CCF CSP 编程题目和解答-----试题名称:相邻数对-------201409-1
- CCF CSP 201409-2画图(C语言)
- CCF CSP 编程题目和解答-----试题名称:画图-------201409-2
- 【CCF CSP】 201409-2 画图(100分)
- [ACM]CCF CSP [201412-5]E题 货物调度
- [ACM]CCF CSP [201509-5]E题 最佳文章【90分】
- CCF CSP 201409-3 字符串匹配
- CCF CSP 201409-2 画图