• Luogu3977 [TJOI2015]棋盘


    Description

    link

    给定一个大小为 (n imes m) 的棋盘,同时给定一个棋子的攻击范围的情况,是一个 (3 imes p) 的矩阵

    要求放置棋子的方案数

    (p le m ,nle 10^6,mle 6)

    Solution

    这真的是阅读理解题,请仔细分析 (0/1) 后判断每个棋子的攻击范围

    然后状压这部分就是一个考验代码能力的部分……(比如我写了俩小时,旁边的 (@happyguy) 就写了半小时……)

    然后这样并不能通过本题,毕竟复杂度在那里……

    然后我们发现这个转移是有向的……(这部分抄了题解……毕竟不会矩阵加速)

    两个状态之间就是两个状态之间的指向性转移

    然后建立初始矩阵,快速幂

    Code

    #include<bits/stdc++.h>
    using namespace std;
    namespace yspm{
    	inline int read()
    	{
    		int res=0,f=1; char k;
    		while(!isdigit(k=getchar())) if(k=='-') f=-1;
    		while(isdigit(k)) res=res*10+k-'0',k=getchar();
    		return res*f;
    	}
    	const int N=1e6+10;
    	bool vis[4][10],abl[100],t1[100][100],t2[100][100];
    	int n,m,k,p,s;
    	#define ui unsigned int
    	struct node{
    		ui a[100][100];
    		ui* operator[](int x){return a[x];}
    		inline void init(){memset(a,0,sizeof(a)); return ;}
    		inline void work(){for(int i=0;i<=s;++i) a[i][i]=1; return ;}
    	}b,a;
    	inline node mul(node a,node b)
    	{
    		node res; res.init();
    		for(int i=0;i<=s;++i)
    		{
    			for(int j=0;j<=s;++j)
    			{
    				for(int k=0;k<=s;++k) res[i][j]+=a[i][k]*b[k][j];
    			}
    		}
    		return res;
    	}
    	inline bool judge1(int x,int y)
    	{
    		if(!abl[x]||!abl[y]) return 0;
    		for(int i=1;i<=m;++i)
    		{
    			if(!(x&(1<<(i-1)))) continue;
    			int t=i-k;
    			for(int j=1;j<=m;++j)
    			{
    				if(j+t<1) continue;
    				if(j+t>m) continue;
    				if(!vis[3][j]) continue;
    				if(y&(1<<(j+t-1))) return 0;
    			}
    		}
    		return 1;
    	}
    	inline bool judge2(int x,int y)
    	{
    		if(!abl[x]||!abl[y]) return 0;
    		for(int i=1;i<=m;++i)
    		{
    			if(!(x&(1<<(i-1)))) continue;
    			int t=i-k;
    			for(int j=1;j<=m;++j)
    			{
    				if(j+t<1) continue;
    				if(j+t>m) continue;
    				if(!vis[1][j]) continue;
    				if(y&(1<<(j+t-1))) return 0;
    			}
    		}
    		return 1;
    	}
    	inline bool c1(int x)
    	{
    		for(int i=1;i<=m;++i)
    		{
    			if(!(x&(1<<(i-1)))) continue;
    			int t=i-k;
    			for(int j=1;j<=p;++j)
    			{
    				if(!vis[2][j]) continue;
    				if(j+t<1) continue;
    				if(j+t>m) continue;
    				if(x&(1<<(j+t-1))) return 0;
    			} 
    		} return 1;
    	}
    	signed main()
    	{	
    		n=read(); m=read(); p=read(); k=read()+1;
    		for(int i=1;i<=3;++i)
    		{
    			for(int j=1;j<=p;++j) vis[i][j]=read();
    		} vis[2][k]=0;
    		s=(1<<m)-1;
    		for(int i=0;i<=s;++i) abl[i]=c1(i);
    		
    		
    		for(int i=0;i<=s;++i)
    		{
    			for(int j=0;j<=s;++j) t1[i][j]=judge1(i,j);
    		}
    	
    		for(int i=0;i<=s;++i) 
    		{
    			for(int j=0;j<=s;++j) t2[i][j]=judge2(i,j);
    		}
    		for(int j=0;j<=s;++j)
    		{
    			for(int k=0;k<=s;++k)
    			{
    				if(t1[j][k]&&t2[k][j]) b[j][k]++;
    			}
    		}
    		a=b; --n; for(;n;n>>=1,a=mul(a,a)) if(n&1) b=mul(b,a);
    		ui ans=0; for(int i=0;i<=s;++i) ans+=b[n][i]; cout<<ans<<endl;
      		return 0;
    	}
    }
    signed main(){return yspm::main();}
    
  • 相关阅读:
    [转]QTP 怎样连接mysql数据库操作
    [转]使用Eclipse来开发Android源码
    组合排序
    插入排序
    冒泡排序
    选择排序
    计数排序
    希尔排序
    合并排序
    鸡尾酒排序
  • 原文地址:https://www.cnblogs.com/yspm/p/13406623.html
Copyright © 2020-2023  润新知