ZOJ-2317 Nice Patterns Strike Back

2 篇文章 0 订阅
1 篇文章 0 订阅

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2317

题意:给一个N*M的矩阵,填黑、白两种颜色,问其中不能有2*2的矩阵是一样颜色的方案数?方案数太大,输出%p之后的结果。

思路:N<10^100,M<=5,一看数据范围就能猜到是在M上研究。因为M非常小,所以我们可以枚举每一列的状态,总共只有2^5=32中状态,这样我们就可以处理出来一个32*32的矩阵,a.m[ i ][ j ]=1表示 i 代表的状态可以和 j 代表的状态相邻,这样只需要求出该矩阵的(N-1)次幂,然后累加矩阵每一个位置的值就是答案。因为N很大,这里做快速幂的时候还要用到高精度!当然也可以用java写更方便一些,懒得下eclipse,就手写高精度了。

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long

int m,p,tm;
string n;
struct node
{
    LL m[33][33];
}a,res;

const int L=150;

string subb(string a,string b)
{
    string ans;
    int na[L]={0},nb[L]={0};
    int la=a.size(),lb=b.size();
    for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
    for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
    int lmax=la>lb?la:lb;
    for(int i=0;i<lmax;i++)
    {
        na[i]-=nb[i];
        if(na[i]<0) na[i]+=10,na[i+1]--;
    }
    while(!na[--lmax]&&lmax>0)  ;lmax++;
    for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
    return ans;
}

int sub(int *a,int *b,int La,int Lb)
{
    if(La<Lb) return -1;
    if(La==Lb)
    {
        for(int i=La-1;i>=0;i--)
            if(a[i]>b[i]) break;
            else if(a[i]<b[i]) return -1;

    }
    for(int i=0;i<La;i++)
    {
        a[i]-=b[i];
        if(a[i]<0) a[i]+=10,a[i+1]--;
    }
    for(int i=La-1;i>=0;i--)
        if(a[i]) return i+1;
    return 0;

}

string div(string n1,string n2,int nn)
{
    string s,v;
     int a[L],b[L],r[L],La=n1.size(),Lb=n2.size(),i,tp=La;
     fill(a,a+L,0);fill(b,b+L,0);fill(r,r+L,0);
     for(i=La-1;i>=0;i--) a[La-1-i]=n1[i]-'0';
     for(i=Lb-1;i>=0;i--) b[Lb-1-i]=n2[i]-'0';
     if(La<Lb || (La==Lb && n1<n2))
     {
        return "0";
     }
     int t=La-Lb;
     for(int i=La-1;i>=0;i--)
        if(i>=t) b[i]=b[i-t];
        else b[i]=0;
     Lb=La;
     for(int j=0;j<=t;j++)
     {
         int temp;
         while((temp=sub(a,b+j,La,Lb-j))>=0)
         {
             La=temp;
             r[t-j]++;
         }
     }
     for(i=0;i<L-10;i++) r[i+1]+=r[i]/10,r[i]%=10;
     while(!r[i]) i--;
     while(i>=0) s+=r[i--]+'0';
     i=tp;
     while(!a[i]) i--;
     while(i>=0) v+=a[i--]+'0';
     if(v.empty()) v="0";
     if(nn==1) return s;
     if(nn==2) return v;
}

void init()
{
    int x[10],y[10];
    for(int i=0;i<tm;i++)
     for(int j=0;j<tm;j++)
    {
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        int k = i;
        while(k)
        {
            if(k % 2 == 0)
              x[++x[0]] = 0;
            else
              x[++x[0]] = 1;
            k >>= 1;
        }
        k = j;
        while(k)
        {
            if(k % 2 == 0)
              y[++y[0]] = 0;
            else
              y[++y[0]] = 1;
            k >>= 1;
        }
        int flag = 0,sum;
        for(int k=1;k<m;k++)
        {
            sum = x[k] + x[k+1] + y[k] + y[k+1];
            if(sum == 0 || sum == 4)
            {
                flag = 1;
                break;
            }
        }
        if(flag)
            a.m[i][j] = 0;
        else
            a.m[i][j] = 1;
    }
}

node mul(node a,node b)
{
    node c;
    for(int i=0;i<tm;i++)
     for(int j=0;j<tm;j++)
    {
        c.m[i][j] = 0;
        for(int k=0;k<tm;k++)
          c.m[i][j] = (c.m[i][j] + a.m[i][k]*b.m[k][j]) % p;
    }
    return c;
}

int  check(string k)
{
    int u = k[k.size()-1] - '0';
    if(u % 2 == 1)
        return 1;
    return 0;
}


void ksm(string k)
{
    memset(res.m,0,sizeof(res.m));
    for(int i=0;i<tm;i++) res.m[i][i] = 1;
    while(k != "0")
    {
        int v = check(k);
        if(v)
            res = mul(res,a);
        a = mul(a,a);
        k = div(k,"2",1);
    }
}

int main()
{
    ios::sync_with_stdio(false);
    int T;
    cin >> T;
    while(T--)
    {
      cin >> n >> m >> p;
      n = subb(n,"1");
      memset(a.m,0,sizeof(a.m));
      tm = 1;
      for(int i=1;i<=m;i++) tm *= 2;
      init();
      ksm(n);
      int ans = 0;
      for(int i=0;i<tm;i++)
       for(int j=0;j<tm;j++)
        ans = (ans+res.m[i][j]) % p;
      cout << ans << endl;
      if(T != 0) cout << endl;
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值