ZOJ -- 2317(矩阵快速幂 + 大数简单处理)

题意:

给定三个参数 b(b<1e100),n(n<5),mod(mod<10000),行数为n列数为b 的0,1 矩阵中有多少个不含--- 边长为2且四个点颜色相同(全1或全0)的正方形。结果对mod取模。

思路:

从任意列状态出发,找到一个可以匹配的列状态,得到转移,那么如果一个状态成功转移b-1次,就是该问题的一个可行解。

由于n很小,列状态最多32个,可以先构造转移矩阵,A(n,n)。其中a(i,j)代表i状态可以与j匹配。显然该矩阵为对称矩阵。

那么A*A中每个元素代表的含义有是什么?

显然每个点 b(i,j) 是有a的第i行和第j列相乘得来的,第i行的每个元素可以定义为 :(经过0次转移,最终经由k转移至i有a(i,k)种方案)

那么A^(b-1)中每个元素a(i,j)的含义就是(经过b-1次转移,最终经由k转移至i有a(i,k)种方案)

该题目就是最终的矩阵元素求和。


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
#define rep(i,n) for(int i=0;i<n;i++)
int mod;
const int maxn = 33;
struct Matrix{
   int m[maxn][maxn];
   void init(){
     for(int i=0;i<33;i++)
         for(int j=0;j<33;j++)
            m[i][j]=(i==j);
   }
   void show(int lim){
      rep(i,lim){
        rep(j,lim) cout<<m[i][j]<<" ";
        cout<<endl;
      }
   }
};
string div2(string s){
  string ans;
  int cnt=0;
  for(int i=0;i<s.length();i++){
      char c=(s[i]-'0'+cnt*10)/2+'0';
      cnt=(cnt*10+s[i]-'0')%2;
      if(!ans.empty()||c!='0') ans+=c;
  }
  if(ans.empty()) ans+='0';
  return ans;
}
int mod2(string s){
   int res=0;
   for(int i=0;i<s.size();i++)
       res=(res*10+s[i]-'0')%2;
   return res;
}
string sub1(string s){
   int res=0;
   for(int i=s.size()-1;i>=0;i--){
       if(s[i]=='0') s[i]='9';
       else{
          s[i]--; break;
       }
   }
   if(s[0]=='0') s=s.substr(1);
   return s;
}
int n;
Matrix mult(Matrix A,Matrix B){
  Matrix C;
  for(int i=0;i<(1<<n);i++)
    for(int j=0;j<(1<<n);j++){
       C.m[i][j]=0;
       for(int k=0;k<(1<<n);k++)
          C.m[i][j]=(C.m[i][j]+A.m[i][k]*B.m[k][j])%mod;
   }
   return C;
}
Matrix Pow(Matrix A,string b){
  Matrix res;
  res.init();
  while(b!="0"){
     if(mod2(b)) res=mult(res,A);
     A=mult(A,A);
     b=div2(b);
  }
  return res;
}
char b[110];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
      scanf("%s %d %d",b,&n,&mod);
      string ss(b); ss=sub1(ss);
      Matrix A;
      for(int i=0;i<(1<<n);i++)
        for(int j=0;j<(1<<n);j++){
          A.m[i][j]=1;
          for(int k=0;k<n-1;k++){
              if(((i>>k)&1) && ((j>>k)&1) && ((i>>(k+1))&1) && ((j>>(k+1))&1)) A.m[i][j]=0;
              if(!((i>>k)&1) && !((j>>k)&1) && !((i>>(k+1))&1) && !((j>>(k+1))&1)) A.m[i][j]=0;
          }
      }
      Matrix res=Pow(A,ss);
      int sum=0;
      rep(i,(1<<n)) rep(j,(1<<n)) sum=(sum+res.m[i][j])%mod;
      cout<<sum<<endl;
      if(T) cout<<endl;
    }
    return 0;
}


你可能感兴趣的:(Algorithm,ZOJ)