1. 程式人生 > >sgu 197 Nice Patterns Strike Back

sgu 197 Nice Patterns Strike Back

題意:鋪馬路,不出現2*2的同顏色的方格的方案數。

由於m很小,因此一行最多有32種塗法。而一行的塗法是從上一行轉移過來的。比如:

m=2時,0表示白磚,1黑磚。

A:00,B:10,C:01,D:11

      A       B       C       D

A    0      1        1       1

B     1      1       1        1

C     1      1       1        1

D    1       1       1         0

i行j列為1表示第k-1行為j狀態時,第k行能轉移到i狀態。這個矩陣相當於斐波那契中的{1,1,1,0}矩陣。也是描述轉移的。用這個矩陣快速冪。

#include <iostream>
#include <cstdio>
#include 
<cmath> #include <algorithm> #include <vector> #include <iomanip> #include <cstring> #include <map> #include <queue> #include <set> #include <cassert> #include <stack> #define mkp make_pair using namespace std; const double EPS=1e-8; typedef
long long lon; const int SZ=50,INF=0x7FFFFFFF; lon arr[SZ][SZ]; int m,mod; string n; bool chk(int x,int y,int m) { int res1=x|y; for(int i=0;i+1<m;++i) { if(!(res1&(1<<i))&&!(res1&(1<<(i+1))))return 0; } int res2=x&y; for(int i=0;i+1<m;++i) { if((res2&(1<<i))&&(res2&(1<<(i+1))))return 0; } return 1; } const int MAX=200; int Subtraction(char num1[], char num2[], int sum[]) { int i, j, len, blag; char *temp; int n2[MAX] = {0}; int len1 = strlen(num1); // 計算陣列num1的長度,即大數的位數 int len2 = strlen(num2); // 計算陣列num2的長度,即大數的位數 // 在進行減法之前要進行一些預處理 blag = 0; // 為0表示結果是正整數,為1表示結果是負整數 if(len1 < len2) // 如果被減數位數小於減數 { blag = 1; // 標記結果為負數 // 交換兩個數,便於計算 temp = num1; num1 = num2; num2 = temp; len = len1; len1 = len2; len2 = len; } else if(len1 ==len2) // 如果被減數的位數等於減數的位數 { // 判斷哪個數大 for(i = 0; i < len1; i++) { if(num1[i] == num2[i]) continue; if(num1[i] > num2[i]) { blag = 0; // 標記結果為正數 break; } else { blag = 1; // 標記結果為負數 // 交換兩個數,便於計算 temp = num1; num1 = num2; num2 = temp; break; } } } len = len1>len2 ? len1 : len2; // 獲取較大的位數 //將num1字元陣列的數字轉換為整型數且逆向儲存在整型陣列sum中,即低位在前,高位在後 for (i = len1-1, j = 0; i >= 0; i--, j++) sum[j] = num1[i] - '0'; // 轉換第二個數 for (i = len2-1, j = 0; i >= 0; i--, j++) n2[j] = num2[i] - '0'; // 將兩個大數相減 for (i = 0; i <= len; i++) { sum[i] = sum[i] - n2[i]; // 兩個數從低位開始相減 if (sum[i] < 0) // 判斷是否有借位 { // 借位 sum[i] += 10; sum[i+1]--; } } // 計算結果長度 for (i = len1-1; i>=0 && sum[i] == 0; i--) ; len = i+1; if(blag==1) { sum[len] = -1; // 在高位新增一個-1表示負數 len++; } return len; // 返回結果的位數 } void init() { cin>>n>>m>>mod; char tmp[200],one[]={'1',0}; copy(n.begin(),n.end(),tmp); tmp[n.size()]=0; int res[200]; int sz=Subtraction(tmp,one,res); for(int i=sz-1;i>=0;--i) { tmp[sz-i-1]=res[i]+'0'; } tmp[sz]=0; n.assign(tmp); //cout<<n<<" "<<sz<<endl; for(int i=0;i<(1<<m);++i) { for(int j=0;j<(1<<m);++j) { if(chk(i,j,m)) { ++arr[i][j]; } } } } void mul(lon x[SZ][SZ],lon y[SZ][SZ],lon res[SZ][SZ],int sz) { int tmp[SZ][SZ]; memset(tmp,0,sizeof(tmp)); for(int i=0;i<sz;++i) { for(int j=0;j<sz;++j) { for(int k=0;k<sz;++k) { tmp[i][j]+=x[i][k]*y[k][j]%mod; } } } for(int i=0;i<sz;++i) { for(int j=0;j<sz;++j) { res[i][j]=tmp[i][j]%mod; } } } void get_d(lon x[SZ][SZ]) { for(int i=0;i<SZ;++i)x[i][i]=1; } int SubStract(int *p1, int len1, int *p2, int len2) { int i; if(len1 < len2) return -1; if(len1 == len2 ) { // 判斷p1 > p2 for(i = len1-1; i >= 0; i--) { if(p1[i] > p2[i]) // 若大,則滿足條件,可做減法 break; else if(p1[i] < p2[i]) // 否則返回-1 return -1; } } for(i = 0; i <= len1-1; i++) // 從低位開始做減法 { p1[i] -= p2[i]; // 相減 if(p1[i] < 0) // 若是否需要借位 { // 借位 p1[i] += 10; p1[i+1]--; } } for(i = len1-1; i >= 0; i--) // 查詢結果的最高位 { if( p1[i] ) //最高位第一個不為0 return (i+1); //得到位數並返回 } return 0; //兩數相等的時候返回0 } int Division(char a1[]) { int DVN=2; int a[102],x=0,c[102]; int L=strlen(a1),L1=1; int i,j; for(i=1;i<=L;i++) a[i]=a1[i-1]-'0';//???????,?????? for(i=1;i<=L;i++) { c[i]=(x*10+a[i])/DVN; x=(x*10+a[i])%DVN;//????? } while(c[L1]==0&&L1<L) L1++; //memset(a1,0,sizeof(a1)); for(i=L1;i<=L;i++) a1[i-L1]=c[i]+'0'; a1[L+1-L1]=0; } void pow_mod() { lon res[SZ][SZ]; memset(res,0,sizeof(res)); get_d(res); for(;n!=""&&n!="0";) { if((n[n.size()-1]-'0')&1) { mul(res,arr,res,1<<m); } mul(arr,arr,arr,1<<m); char tmp[MAX]; for(int i=0;i<n.size();++i) { tmp[i]=n[i]; } tmp[n.size()]=0; // char two[]={'2',0}; Division(tmp); n.assign(tmp); //cout<<" "<<(n=="")<<endl; //cout<<n<<endl; } for(int i=0;i<(1<<m);++i) { for(int j=0;j<(1<<m);++j) { arr[i][j]=res[i][j]; } } } int main() { //std::ios::sync_with_stdio(0); //freopen("d:\\1.txt","r",stdin); lon casenum; //cin>>casenum; //for(lon time=1;time<=casenum;++time) { init(); // if(n=="1"&&m==2&&mod==5) // { // for(int i=0;i<100000;++i)++arr[i][i]; // } if(n=="0"&&m==1) { cout<<2%mod<<endl; return 0; } pow_mod(); int res=0; for(int i=0;i<(1<<m);++i) { for(int j=0;j<(1<<m);++j) { res+=arr[i][j]; } } cout<<res%mod<<endl; } return 0; }