题目:Light oj 1332 - Kings in Chessboard
题意:对一个n*10的棋盘,像扫雷一样的每列放两个kings,求方案数
思路:构造转移矩阵 = =
技巧:对于2^32或者2^64的操作可以直接忽略,最后根据正负处理
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;
struct Matrix
{
int m[40][40];
}E,D;
int n_num=0;
int num[110];
bool is_ok(int n)
{
if(__builtin_popcount(n)!=2)
return false;
string s="";
int tmp=n;
while(tmp)
{
if(tmp%2==1)
s="1"+s;
else
s="0"+s;
tmp/=2;
}
while(s.size()<10)
s="0"+s;
for(int i=0;i<9;i++)
if(s[i]=='1'&&s[i+1]=='1')
return false;
return true;
}
bool is_right(int x,int y)
{
string s="",t="";
int cnt=x,tmp=y;
while(cnt)
{
if(cnt&1)
s="1"+s;
else
s="0"+s;
cnt/=2;
}
while(tmp)
{
if(tmp&1)
t="1"+t;
else
t="0"+t;
tmp/=2;
}
while(s.size()<10)
s="0"+s;
while(t.size()<10)
t="0"+t;
for(int i=0;i<=9;i++)
{
if(s[i]=='1')
{
if(i-1>=0)
{
if(t[i-1]=='1')
return false;
}
if(i+1<=10)
{
if(t[i+1]=='1')
return false;
}
if(t[i]=='1')
return false;
}
}
return true;
}
void Pre()
{
for(int i=1;i<=(1<<9)+(1<<8);i++)
{
if(is_ok(i))
num[++n_num]=i;
}
memset(D.m,0,sizeof(D.m));
for(int i=1;i<=n_num;i++)
for(int j=1;j<=n_num;j++)
{
if(is_right(num[i],num[j]))
D.m[i][j]=1;
}
}
void init()
{
for(int i=1;i<=n_num;i++)
for(int j=1;j<=n_num;j++)
E.m[i][j]=(i==j);
}
Matrix Multi(Matrix A,Matrix B)
{
Matrix ans;
for(int i=1;i<=n_num;i++)
for(int j=1;j<=n_num;j++)
{
ans.m[i][j]=0;
for(int k=1;k<=n_num;k++)
ans.m[i][j]+=A.m[i][k]*B.m[k][j];
}
return ans;
}
Matrix Pow(Matrix A,int k)
{
Matrix ans=E;
while(k)
{
if(k&1)
{
k--;
ans=Multi(ans,A);
}
else
{
k/=2;
A=Multi(A,A);
}
}
return ans;
}
int main()
{
Pre();
init();
/*
for(int i=1;i<=n_num;i++)
{
for(int j=1;j<=n_num;j++)
printf("%d ",D.m[i][j]);
printf("\n");
}*/
int t;
scanf("%d",&t);
for(int cases=1;cases<=t;cases++)
{
int n;
scanf("%d",&n);
Matrix tmp=Pow(D,n-1);
Matrix cnt;
for(int i=1;i<=n_num;i++)
cnt.m[i][1]=1;
Matrix ans;
for(int i=1;i<=n_num;i++)
for(int j=1;j<=1;j++)
{
ans.m[i][j]=0;
for(int k=1;k<=n_num;k++)
ans.m[i][j]+=tmp.m[i][k]*cnt.m[k][j];
}
int sy=0;
for(int i=1;i<=n_num;i++)
sy+=ans.m[i][1];
long long pp=1;
pp<<=32;
if(sy<0)
sy=pp+sy;
printf("Case %d: %lld\n",cases,sy);
}
return 0;
}
尼玛 前天浑浑噩噩的 跟喵呜大神说 这个题是 10*n 的棋盘,一共只放两个kings,那我该怎么处理当前的状态确保前面是否已经存在这样的两个kings了呢,然后巴拉巴拉各种混乱(然后才发现题目看错了)
好吧 那下面贴一个与本题不大相关的代码,就是把题目的每行恰有两个kings,变成整个棋盘只有两个kings的方案数
膜拜喵呜大神
// 膜拜喵呜~
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
#define MOD 4294967296ll
typedef struct
{
unsigned long long a[70][70];
}Matrix;
typedef struct
{
int st,num;
}State;
State av[70];
int two[1025];
int up;
Matrix ch,ans;
Matrix Mul(Matrix x,Matrix y)
{
int i,j,k;
Matrix ret;
for (i=0;i<up;i++)
{
for (j=0;j<up;j++)
{
ret.a[i][j]=0;
for (k=0;k<up;k++)
{
ret.a[i][j]=(ret.a[i][j]+(x.a[i][k]*y.a[k][j])%MOD)%MOD;
}
}
}
return ret;
}
unsigned long long F_pow(int n)
{
Matrix ret=ans;
Matrix x=ch;
int i;
while(n)
{
if (n & 1) ret=Mul(x,ret);
x=Mul(x,x);
n>>=1;
}/*
for (i=0;i<up;i++)
{
for (int j=0;j<up;j++)
cout<<x.a[i][j]<<" ";
cout<<endl;
}*/
unsigned long long r=0;
for (i=0;i<up;i++)
{
//cout<<ret.a[i][0]<<endl;
if (av[i].num==2) r=(r+ret.a[i][0])%MOD;
}
return r;
}
bool Check(State x,State y)
{
int i,s=0;
if (x.num>y.num) return false;
if (x.num+two[y.st]!=y.num) return false;
if (((x.st<<1) & y.st)!=0) return false;
if (((x.st>>1) & y.st)!=0) return false;
if ((x.st & y.st)!=0) return false;
//printf("%d %d->%d %d\n",x.st,x.num,y.st,y.num);
return true;
}
void Pre()
{
int i,j;
up=0;
memset(two,0,sizeof(two));
for (i=0;i<(1<<10);i++)
{
for (j=0;j<10;j++)
{
if ((i & (1<<j))!=0) two[i]++;
}
}
for (i=0;i<10;i++)
{
for (j=i+2;j<10;j++)
{
av[up].st=(1<<i)|(1<<j);
av[up++].num=2;
}
}
for (i=0;i<10;i++)
{
av[up].st=(1<<i);
av[up++].num=1;
av[up].st=(1<<i);
av[up++].num=2;
}
av[up].st=0;
av[up++].num=0;
av[up].st=0;
av[up++].num=1;
av[up].st=0;
av[up++].num=2;
for (i=0;i<up;i++)
{
for (j=0;j<up;j++)
{
if (Check(av[i],av[j])) ch.a[j][i]=1;
else ch.a[j][i]=0;
}
}
memset(ans.a,0,sizeof(ans.a));
for (i=0;i<up;i++)
{
if (two[av[i].st]==av[i].num) ans.a[i][0]=1;
}
}
int main()
{
int i,j,n,T;
Matrix s;
scanf("%d",&T);
Pre();
while(T--)
{
scanf("%d",&n);
cout<<F_pow(n-1)<<endl;
}
return 0;
}