zoukankan      html  css  js  c++  java
  • 「HDU」5434 Peaceful Small Elephant (状压)

    题意:原题在这


    给出一个棋盘大小,一只小象可以跳这一格直角顶点所对的格子(及左上右上左下右下),且两只互不能攻击的小象还可以合体,合体之后攻击范围进行合并(见图)。求有多少种能使小象互不攻击的摆放方案

    做法:

    1. 由题可知:合并的小象其实是攻击范围变小了


    2. 如果坐标(i,j),(i+1,j+1)存在小象,那么必须保证(i+1,j),(i,j+1)两个位置至少有一个棋子,可以得到状态转移矩阵。


    3. 然后状压+矩阵快速幂

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define mod 1000000007
    #define inf 9999999999
    using namespace std;
    int n,m,p,digit;
    bool w[128][128];
    
    struct node
    {
        long long r[1<<8][1<<8];
    }ans,base;
    
    node multi(node a,node b)
    {
        node count;
        for(int i=0;i<digit;i++)
        for(int j=0;j<digit;j++)
        {
            count.r[i][j]=0;
        }
        for(int i=0;i<digit;i++)
        for(int j=0;j<digit;j++)
        for(int k=0;k<digit;k++)
        {
            count.r[i][j]=(count.r[i][j]+(long long)(a.r[i][k]*b.r[k][j])%mod)%mod;
        }
        return count;
    }
    
    node pow(long long p)
    {
        node result;
        for(int i=0;i<(1<<8);i++)
        for(int j=0;j<(1<<8);j++)
        {
            result.r[i][j]=0;
        }
        for(int i=0;i<(1<<m);i++)
        {
            result.r[i][i]=1;
        }
        for(int i=0;i<(1<<m);i++)
        for(int j=0;j<(1<<m);j++)
        {
            base.r[i][j]=w[i][j];
        }
        while(p)
        {
            if(p%2) result=multi(result,base);
            p>>=1;
            base=multi(base,base);
        }
        return result;
    }
    
    bool check(int x,int y)//是否冲突
    {
        for(int i=0;i<m;i++)
        {
            int k=1<<i;
            if(x&k)
            {
                if(i!=0)
                {
                    if((y&(1<<i-1))&&!(x&(1<<i-1))&&!(y&(1<<i))) return false;
                }
                if(i!=m-1)
                {
                    if((y&(1<<i+1))&&!(x&(1<<i+1))&&!(y&(1<<i))) return false;
                }
            }
        }
        return true;
    }
    
    void matrix()
    {
        for(int i=0;i<digit;i++)
        for(int j=0;j<digit;j++)
        {
            if(check(i,j)) w[i][j]=1;
        }
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            memset(w,0,sizeof(w));
            digit=1<<m;
            matrix();
            node ans1=pow(n);
            node ans2;
            for(int i=0;i<128;i++)
            for(int j=0;j<128;j++)
            {
                ans2.r[i][j]=0;
                ans2.r[0][0]=1;
            }
            ans2=multi(ans2,ans1);
            int sum=0;
            for(int i=0;i<digit;i++)
            for(int j=0;j<digit;j++)
            {
                sum=(sum+ans2.r[i][j])%mod;
            }
            cout<<sum<<endl;
        }
        return 0;
    }
  • 相关阅读:
    db2中的常用命令及使用方法
    互联网服务应用协议设计
    Zookeeper整理(一)- 写操作产生事件,写操作与Watcher对应关系
    实现自己的连接池(一)
    SMP、NUMA、MPP体系结构介绍
    随手备忘 ubuntu12.04 lts 安装gcc 4.8
    认真体会 结构体中的零长度数组
    由内存池实现总结内存对齐问题
    认真理解 oom killer 备忘
    仔细体会 epoll中的et lt模式
  • 原文地址:https://www.cnblogs.com/LocaEtric/p/9614265.html
Copyright © 2011-2022 走看看