zoukankan      html  css  js  c++  java
  • [TJOI2015] 棋盘

    Description

    为了提高智商,ZJY去新世界旅游了。可是旅游过后的ZJY杯具的发现要打开通往原来世界的门,必须要解开门上面画的谜题。谜题是这样的:有个(n)(m)列的棋盘,棋盘上可以放许多特殊的棋子。每个棋子的攻击范围是(3)行,(p)列。输入数据用一个(3 imes p)的矩阵给出了棋子攻击范围的模板,棋子被默认为模板中的第(1)行,第(k)列,则棋子能攻击到的位置是(1),不能攻击到的位置是(0)(1leq pleq m,0leq k<p)。输入数据保证第(1)行第(k)列的位置是(1)。打开门的密码就是,在要求棋子互相不能攻击到的前提下,摆放棋子的方案数。注意什么棋子都不摆放也算作一种可行方案。由于方案数可能很大,而密码为(32)位的二进制密码,所以ZJY仅需要知道方案数对(2^{32})取余数的结果即可。

    Input

    输入数据的第一行为两个整数(n)(m),表示棋盘的大小。第二行为两个整数(p)(k),表示接下来的攻击范围模板的大小,以及棋子在模板中的位置。接下来三行,每行有(P)个数,表示攻击范围的模版。每个数字后有一个空格。

    Output

    输出数据仅有一行,一个整数,表示可行的方案数模(2^{32})的余数。

    Range

    对于(10\%)(1 leq n leq 5,1 leq m leq 5)

    对于(50\%)(1 leq n leq 1000,1 leq m leq 6)

    对于(100\%)(1leq nleq 1000000,1leq mleq 6)

    Solution

    恶心题。
    被这题卡了一天。

    首先注意到它的行和列是从 (0) 开始标号的,所以第 (1) 行第 (p) 列其实是中间一行的某一列。

    预处理出所有能摆放和两行之间能转移的情况。
    这里要用位运算,最开始拿数组模拟每位弄了半天还是错的,用位运算一下就出来了。

    观察到转移可以用矩阵加速,于是一个矩阵快速幂敲上去就行了。

    注意最后求答案矩阵的时候要新开一个数组不能直接在 (f) 数组上面求!

    Code

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #define int unsigned long long
    
    int maxn;
    int mp[5];
    int n,m,p,k;
    bool vis[105];
    int f[70][70];
    const int mod=4294967296;
    
    struct Matrix{
        int a[100][100];
    
        void clear(){
            memset(a,0,sizeof a);
        }
    
        void init(){
            for(int i=0;i<maxn;i++)
                a[i][i]=1;
        }
    
        Matrix operator*(const Matrix &x)const{
            Matrix z; z.clear();
            for(int i=0;i<maxn;i++){
                for(int j=0;j<maxn;j++){
                    for(int k=0;k<maxn;k++){
                        z.a[i][j]+=(x.a[i][k]*a[k][j])%mod;
                        z.a[i][j]%=mod;
                    }
                }
            }
            return z;
        }
    
        void print(){
            for(int i=0;i<maxn;i++){
                for(int j=0;j<maxn;j++)
                    printf("i=%lld,j=%lld,a=%lld
    ",i,j,a[i][j]);
            }
            puts("");
            for(int i=0;i<maxn;i++){
                for(int j=0;j<maxn;j++)
                    printf("%lld",a[i][j]);
                puts("");
            }
        }
    }M;
    
    void read(int &x){
        x=0; char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    }
    
    bool check(int x){
    	for(int i=1;i<=m;i++){
    		if(x&(1<<i-1)){
    			if(p-k+1<=i){
    				if((x&(mp[2]<<(i+k-p-1)))!=(1ll<<(i-1))){
    					//printf("x=%lld,i=%lld
    ",x,i);
    					//printf("i-1=%lld,1<<i-1=%lld
    ",i-1,1<<i-1);
    					//printf("i+k-p-1=%lld,mp[2]<<=%lld,x&=%lld,1<<=%lld
    ",i+k-p-1,mp[2]<<i+k-p-1,x&(mp[2]<<i+k-p-1),1ll<<(i-1));
    					return 0;
    				}
    			}
    			else{
    				if((x&(mp[2]>>(p-k+1-i)))!=(1ll<<i-1))
    					return 0;
    			}
    		}
    	}
    	return 1;
    }
    
    bool judge(int x,int y){
    	for(int i=1;i<=m;i++){
    		if(x&(1<<i-1)){
    			if(p-k+1<=i){
    				if((y&(mp[3]<<(i+k-p-1))))
    					return 0;
    			}
    			else{
    				if((y&(mp[3]>>(p-k+1-i))))
    					return 0;
    			}
    		}
    		if(y&(1<<i-1)){
    			if(p-k+1<=i){
    				if((x&(mp[1]<<(i+k-p-1))))
    					return 0;
    			}
    			else{
    				if((x&(mp[1]>>(p-k+1-i))))
    					return 0;
    			}
    		}
    	}
    	return 1;
    }
    
    Matrix ksm(Matrix a,int b,int c){
        Matrix ans; ans.init();
        while(b){
            if(b&1)
                ans=ans*a;
            a=a*a;
            b>>=1;
        }
        return ans;
    }
    
    void mul(int a[70][70],int b[70][70],int c[70][70])
    {
        int ret[70][70];
        memset(ret,0,sizeof ret);
        for(int i=0;i<maxn;i++)
         for(int k=0;k<maxn;k++)
          for(int j=0;j<maxn;j++)
          {
               ret[i][j]=(ret[i][j]+a[i][k]*b[k][j]%mod)%mod;
          }
        memcpy(c,ret,sizeof ret);
    }
    
    int a[70][70];
    int ans[70][70];
    
    void qm(int y)
    {
    	for(int i=0;i<maxn;i++)
    		ans[i][i]=1;
        while(y)
        {
            if(y&1) mul(ans,a,ans);
            mul(a,a,a);
            y>>=1;
        }
    }
    
    signed main(){
        read(n),read(m),read(p),read(k); k++;
        maxn=1<<m;
        for(int i=1;i<=3;i++){
            for(int x,j=1;j<=p;j++){
                read(x);
                if(x)
                	mp[i]|=1<<p-j;
            }
        }
       Matrix aa; aa.clear();
        for(int i=0;i<maxn;i++){
            if(check(i)){
                vis[i]=1,f[0][i]=1;
                //printf("i=%lld
    ",i);
            }
        }
        for(int i=0;i<maxn;i++){
            for(int j=0;j<maxn;j++){
                if(vis[i] and vis[j]){
                    if(judge(i,j)){
                        //printf("i=%lld,j=%lld
    ",i,j);
                        aa.a[j][i]=1;
                    }
                }
            }
        }
        /*for(int i=0;i<maxn;i++)
            a[0][i]=a[i][0]=1;*/
        //aa.print();
        Matrix b=ksm(aa,n-1,mod);
        int c[70][70]; memset(c,0,sizeof c);
        for(int i=0;i<maxn;i++){
        	for(int j=0;j<maxn;j++){
        		for(int k=0;k<maxn;k++)
        			(c[i][j]+=f[i][k]*b.a[k][j])%=mod;
        	}
        }
        /*qm(n-1);
        mul(f,ans,ans);*/
        int sum=0;
        for(int i=0;i<maxn;i++){
            for(int j=0;j<maxn;j++)
                (sum+=c[i][j])%=mod;
        }
        printf("%llu
    ",sum%mod);
        return 0;
    }
    
  • 相关阅读:
    7maven依赖排除
    5maven生命周期
    4maven依赖范围、依赖有效性
    3maven常用命令和配置依赖
    1maven概念作用
    6在Eclipse中创建maven和修改默认配置
    2maven下载与配置
    Class 'org.apache.tomcat.jdbc.pool.DataSource' not found
    17 alternatives to your default image viewer on Fedora
    zip压缩包解压后的文件名是乱码?
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/9073795.html
Copyright © 2011-2022 走看看