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;
}

猜你喜欢

转载自www.cnblogs.com/gaudar/p/9808787.html
sgu