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

题意:给你一个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;
			else
				tail = 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值