ZOJ 2317 高精度+状压DP+矩阵快速幂

来源:互联网 发布:sql酒店管理系统 编辑:程序博客网 时间:2024/06/05 08:40

题意:给你一个NxM的格子,每个格子可以涂黑色或者白色,但是不允许任意2x2的格子同色,最多有多少方案。


分析:注意要判断一个pattern是不是nice的,只要检查相邻的两行的状态。由于m很小,可以将行的状态用2^m的掩码来表示,dp[k][i]表示k行,最后一行状态为i的pattern个数,如果状态i和状态j不冲突,那么dp[k+1][j]+=dp[k][i]。由于问题中n很大,这样一行一行转移的动态规划肯定是吃不消的。注意每次的转移其实都是一样的,记dp[k]为一个列向量,建立一个2m*2m的01矩阵A,矩阵元素对应表示两行状态是否冲突,则dp[k+1]=A*dp[k],dp[n]=A^n*dp[0],而A^n可以利用经典的快速乘法运算来计算。


代码:

#pragma comment(linker,"/STACK:102400000,102400000")#include <iostream>#include <string.h>#include <stdio.h>#include <algorithm>#include <vector>#include <string>#include <math.h>#include <queue>#include <stack>#include <map>#include <set>using namespace std;typedef long long ll;const int INF=1000000000;const int maxlength=9999;class bigint{public:int oper, length, a[maxlength];bigint(int = 0);~bigint();void check();void operator = (bigint m);void operator = (int m);void operator = (char *s);bool operator < (bigint m);bool operator <= (bigint m);bool operator > (bigint m);bool operator >= (bigint m);bool operator == (bigint m);bool operator != (bigint m);bigint operator - ();bigint operator + (bigint m);void operator += (bigint m);bigint operator - (bigint m);void operator -= (bigint m);bigint operator * (bigint m);bigint operator * (int m);void operator *= (bigint m);void operator *= (int m);bigint operator / (bigint m);bigint operator / (int m);void operator /= (bigint m);void operator /= (int m);bigint operator % (bigint m);bigint operator % (int m);void operator %= (bigint m);void operator %= (int m);};bigint::bigint(int v){(*this) = v;this -> check();}bigint::~bigint(){}void bigint::check(){for(; length > 0 && a[length] == 0; length--);if(length == 0)oper = 1;}void bigint::operator = (bigint m){oper = m.oper;length = m.length;memcpy(a, m.a, maxlength * sizeof(int));this -> check();}void bigint::operator = (int m){oper = (m > 0)? 1: -1;m = abs(m);memset(a, 0, maxlength*sizeof(int));for(length = 0; m > 0; m = m / 10000)a[++length] = m % 10000;this -> check();}void bigint::operator = (char *s){int i, L;(*this) = 0;if(s[0] == '-' || s[0] == '+'){if(s[0] == '-')oper = -1;L = strlen(s);for(i = 0; i < L; i++)s[i] = s[i+1];}L = strlen(s);length = (L + 3) / 4;for(i = 0; i < L; i++)a[(L - i + 3) / 4] = a[(L - i + 3) / 4] * 10 + (s[i] - 48);this -> check();}bool bigint::operator < (bigint m){if(oper != m.oper)return oper < m.oper;if(length != m.length)return oper * length < m.length * oper;for(int i = length; i >= 1; i--)if(a[i]!=m.a[i])return a[i]*oper<m.a[i]*oper;return false;}bool bigint::operator <= (bigint m){return !(m < (*this));}bool bigint::operator>(bigint m){return m < (*this);}bool bigint::operator >= (bigint m){return !((*this) < m);}bool bigint::operator == (bigint m){return (!((*this) < m)) && (!(m < (*this)));}bool bigint::operator != (bigint m){return ((*this) < m) || (m < (*this));}bigint bigint::operator - (){bigint c = (*this);c.oper = -c.oper;c.check();return c;}bigint abs(bigint m){bigint c = m;c.oper = abs(c.oper);c.check();return c;}bigint bigint::operator + (bigint m){if(m.length == 0)return (*this);if(length == 0)return m;if(oper == m.oper){bigint c;c.oper = oper;c.length = max(length, m.length) + 1;for(int i = 1, temp = 0; i <= c.length; i++)c.a[i] = (temp = (temp / 10000 + a[i] + m.a[i])) % 10000;c.check();return c;}return (*this) - (-m);}bigint bigint::operator - (bigint m){if(m.length == 0)return (*this);if(length == 0)return (-m);if(oper == m.oper){bigint c;if(abs(*this) >= abs(m)){c.oper = oper;c.length = length;for (int i = 1, temp = 0; i <= length; i++)c.a[i] = ((temp = (-int(temp < 0) + a[i] - m.a[i])) + 10000) % 10000;c.check();return c;}return -(m - (*this));}return (*this) + (-m);}bigint bigint::operator * (bigint m){bigint c;c.oper = oper * m.oper;c.length = length + m.length;for(int i = 1; i <= m.length; i++){int number = m.a[i],j,temp = 0;for (j = 1; j <= length; j++)c.a[i + j - 1] += number * a[j];if (i % 10 == 0 || i == m.length)for (j = 1; j <= c.length; j++)c.a[j] = (temp = (temp / 10000) + c.a[j]) % 10000;}c.check();return c;}bigint bigint::operator * (int m){if(m < 0)return -((*this) * (-m));if(m > 100000)return (*this) * bigint(m);bigint c;c.length = length + 2;c.oper = oper;int t = 0;for(int i = 1; i <= c.length; i++)c.a[i] = (t = (t / 10000 + a[i] * m)) % 10000;c.check();return c;}bigint bigint::operator / (bigint m){if(m.length == 0){printf("Division by zero.\n");exit(0);}if(abs(*this) < abs(m))return 0;bigint c, left;c.oper = oper / m.oper;m.oper = 1;c.length = length - m.length + 1;left.length = m.length - 1;memcpy(left.a + 1, a + length - left.length + 1, left.length * sizeof(int));for(int i = c.length; i >= 1; i--){left = left * 10000 + a[i];int head = 0, tail = 10000, mid;while(head + 1 < tail){mid = (head + tail) >> 1;if(m * mid <= left)head = mid;elsetail = mid;}c.a[i] = head;left -= m * head;}c.check();return c;}bigint bigint::operator / (int m){if(m < 0)return -((*this) / (-m));if(m > 100000)return (*this) / bigint(m);bigint c;c.oper = oper;c.length = length;int t = 0;for(int i = c.length; i >= 1; i--)c.a[i] = (t = (t % m * 10000 + a[i])) / m;c.check();return c;}bigint bigint::operator % (bigint m){return (*this) - ((*this) / m) * m;}bigint bigint::operator % (int m){if (m < 0)return -((*this) % (-m));if (m > 100000)return (*this) % bigint(m);int t = 0;for(int i = length; i >= 1; i--)t = (t * 10000 + a[i]) % m;return t;}void bigint::operator += (bigint m){(*this) = (*this) + m;}void bigint::operator -= (bigint m){(*this) = (*this) - m;}void bigint::operator *= (bigint m){(*this) = (*this) * m;}void bigint::operator /= (bigint m){(*this) = (*this) / m;}void bigint::operator %= (bigint m){(*this) = (*this) % m;}void bigint::operator *= (int m){(*this) = (*this) * m;}void bigint::operator /= (int m){(*this) = (*this) / m;}void bigint::operator %= (int m){(*this) = (*this) % m;}int mod;const int maxn=40;struct p{    int m[maxn][maxn];    int h,l;    p()    {        memset(m,0,sizeof(m));    }};p multi(p a,p b){    int i,j,k;    p c;    for(i=1;i<=a.h;i++)    {        for(j=1;j<=b.l;j++)        {            c.m[i][j]=0;            for(k=1;k<=a.h;k++)                c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%mod;        }    }    c.h=a.h;   c.l=b.l;    return c;}p quickpow(p a,bigint n){    int i;    p s;    s.h=s.l=a.h;    for(i=1;i<=a.h;i++)        s.m[i][i]=1;    while(n!=0)    {        if(n%2!=0)            s=multi(s,a);        a=multi(a,a);        n=n/2;    }    return s;}void qs(int* a,int ws,int shu){    int ans=0,i;    for(int i=1;i<=ws;i++)a[i]=0;    while(shu)    {        a[++ans]=shu%2;        shu=shu/2;    }    for(i=1;i<=ws/2;i++)swap(a[i],a[ws-i+1]);    //for(i=1;i<=ws;i++)printf("%d",a[i]);    //printf("\n");}int pd(int* a,int* b,int ws){    for(int i=1;i<ws;i++)if(a[i]==a[i+1]&&b[i]==b[i+1]&&a[i]==b[i])return 0;    return 1;}int main(){    int t,m,i,j,mp[35][35],a[7],b[7],ret,cs=0;char s[10000];bigint B;scanf("%d",&t);while(t--){    if(cs>0)printf("\n");    cs++;    scanf("%s%d%d",s,&m,&mod);    B=s;    for(i=0;i<(1<<m);i++){        qs(a,m,i);        for(j=i;j<(1<<m);j++){            qs(b,m,j);            if(pd(a,b,m))mp[i+1][j+1]=1;            else mp[i+1][j+1]=0;        }    }    for(i=1;i<=(1<<m);i++)        for(j=1;j<=i;j++)mp[i][j]=mp[j][i];        //for(i=1;i<=(1<<m);i++){            //for(j=1;j<=(1<<m);j++)printf("%d",mp[i][j]);            //printf("\n");       // }        p c;        for(i=1;i<=(1<<m);i++)        for(j=1;j<=(1<<m);j++)c.m[i][j]=mp[i][j];        c.h=c.l=(1<<m);        c=quickpow(c,B-1); ret=0;        for(i=1;i<=(1<<m);i++){            for(j=1;j<=(1<<m);j++)ret+=c.m[i][j];        }        printf("%d\n",ret%mod);}return 0;}




0 0
原创粉丝点击