快速幂模板
#define N 150 struct martix{ LL mar[N][N]; martix(){ memset(mar,0,sizeof (mar)); } inline void build(){ FOR(i,0,N) mar[i][i]=1; return; } inline void clear(){ memset(mar,0,sizeof (mar)); return; } } aa; martix operator *(const martix &a, const martix &b){ martix c; //c.clear(); FOR(k,0,N) FOR(i,0,N){ if(a.mar[i][k]<=0) continue; FOR(j,0,N){ if(b.mar[k][j]<=0) continue; c.mar[i][j]+=a.mar[i][k]*b.mar[k][j]; } } return c; } martix operator ^( martix a, LL k){ martix x=a,tmp; LL pow=k; tmp.clear();tmp.build(); while(pow){ if(pow&1) tmp=x*tmp; x=x*x; pow>>=1; } return tmp; }
需要注意的说开200X200以上可能爆栈,这时候必须把封装去了
技巧1:对矩阵Ak次幂求和可以构造矩阵
A E
0 E
新矩阵的k+1次幂的右上即为所求
技巧2:齐次递推数列可以构造矩阵快速求出
将所有项看作列向量就可以很方便地构造,若要求多项和,只需在构造的矩阵中加一列即可
技巧3:从u到v恰好走k步
转移矩阵k次幂即可
VIJOS 1049
//#define LOCAL #include <cstring> #include <iostream> #include <sstream> #include <fstream> #include <string> #include <vector> #include <deque> #include <queue> #include <stack> #include <set> #include <map> #include <algorithm> #include <functional> #include <utility> #include <bitset> #include <cmath> #include <cstdlib> #include <ctime> #include <cstdio> using namespace std; #define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z)) // X_INIT=0 mem_Macro #define INF 0x3f3f3f3f #define MOD 1000000007 #define FOR(i,j,k) for(int i=j;i<k;i+=1) #define FORD(i,j,k) for(int i=j;i>k;i-=1) #define uLL unsigned long long #define LL long long #define SZ(x) int(x.size()) #define pb push_back #define N 150 //int MOD; struct martix{ LL mar[N][N]; martix(){ memset(mar,0,sizeof (mar)); } inline void build(){ FOR(i,0,N) mar[i][i]=1; return; } inline void clear(){ memset(mar,0,sizeof (mar)); return; } } aa; martix operator *(const martix &a, const martix &b){ martix c; //c.clear(); FOR(k,0,N) FOR(i,0,N){ if(a.mar[i][k]<=0) continue; FOR(j,0,N){ if(b.mar[k][j]<=0) continue; c.mar[i][j]+=a.mar[i][k]*b.mar[k][j]; // c.mar[i][j]%=MOD; } } return c; } martix operator ^( martix a, LL k){ martix x=a,tmp; LL pow=k; tmp.clear();tmp.build(); while(pow){ if(pow&1) tmp=x*tmp; x=x*x; pow>>=1; } return tmp; } int main(){ #ifdef LOCAL freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif int n,m,k; scanf("%d%d%d",&n,&m,&k); int a[11][110]; //cout<<"*"; martix tmp,ans; ans.build(); FOR(i,0,m){ tmp.clear(); FOR(j,0,n) scanf("%d",&a[i][j]),tmp.mar[j][a[i][j]-1]=1; ans=tmp*ans; } ans=ans^(k/m); FOR(i,0,k%m){ tmp.clear(); FOR(j,0,n) tmp.mar[j][a[i][j]-1]=1; ans=tmp*ans; } int anss[110]; FOR(i,0,n) FOR(j,0,n) if(ans.mar[i][j]) anss[i]=j; /*FOR(i,0,n) {FOR(j,0,n) cout<<tmp.mar[i][j]; cout<<endl; } FOR(i,0,k%m) FOR(j,0,n) anss[j]=anss[a[i][j]-1]; //anss[j]=a[i][j]-1;*/ FOR(i,0,n) cout<<anss[i]+1<<' '; //system("pause"); #ifdef LOCAL fclose(stdin); fclose(stdout); #endif return 0; }
VIJOS 1194
//#define LOCAL #include <cstring> #include <iostream> #include <sstream> #include <fstream> #include <string> #include <vector> #include <deque> #include <queue> #include <stack> #include <set> #include <map> #include <algorithm> #include <functional> #include <utility> #include <bitset> #include <cmath> #include <cstdlib> #include <ctime> #include <cstdio> using namespace std; #define X_mem(x,y,z) (X_mem[x][y][z] ? X_mem[x][y][z] :X_mem[x][y][z]=mem(x,y,z)) // X_INIT=0 mem_Macro #define INF 0x3f3f3f3f #define MOD 1000000007 #define FOR(i,j,k) for(int i=j;i<k;i+=1) #define FORD(i,j,k) for(int i=j;i>k;i-=1) #define uLL unsigned long long #define LL long long #define SZ(x) int(x.size()) #define pb push_back #define N 150 //int MOD; int p; struct martix{ LL mar[N][N]; martix(){ memset(mar,0,sizeof (mar)); } inline void build(){ FOR(i,0,N) mar[i][i]=1; return; } inline void clear(){ memset(mar,0,sizeof (mar)); return; } } aa; martix operator *(const martix &a, const martix &b){ martix c; //c.clear(); FOR(k,0,N) FOR(i,0,N){ if(a.mar[i][k]<=0) continue; FOR(j,0,N){ if(b.mar[k][j]<=0) continue; c.mar[i][j]+=a.mar[i][k]*b.mar[k][j]; c.mar[i][j]%=p; } } return c; } martix operator ^( martix a, LL k){ martix x=a,tmp; LL pow=k; tmp.clear();tmp.build(); while(pow){ if(pow&1) tmp=x*tmp; x=x*x; pow>>=1; } return tmp; } int main(){ #ifdef LOCAL freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif int n,m; scanf("%d%d%d",&n,&m,&p); map<int,int> idx; idx[0]=1;idx[3]=1;idx[6]=1;idx[12]=1;idx[15]=1;idx[24]=1;idx[27]=1;idx[30]=1; int l=1<<m; FOR(i,0,l) FOR(j,0,l){ if((i|j)==l-1)if(idx[(i)&j]) aa.mar[i][j]=1; } aa=aa^n;/* FOR(i,0,l){ FOR(j,0,l) cout<<aa.mar[i][j]; cout<<endl;}*/ cout<<aa.mar[l-1][l-1]; #ifdef LOCAL fclose(stdin); fclose(stdout); #endif return 0; }
神题,要求用1x2全覆盖NxM
由于n,m极度的不均匀(m<5,n<1e9),而1X2最多影响两行,所以考虑一个状态转移矩阵
状态为单独一行被覆盖的格子的二进制表示,预设前面的行已经被全覆盖。则步进的状态转移就可以看作在全覆盖当前行且最大影响范围不超过下一行的前提下任意的摆放结果(只看下一行的覆盖情况)
转移的条件是(i|j)==1<<m-1(保证前一行被全覆盖,因为如过前一行这一位被覆盖,则无关紧要必为1,否则则需要下一行这一位为一(骨牌竖放))和i&j表示的状态能被横着骨牌覆盖