• 【数学(矩阵加速)】AcWing 206. 石头游戏


    这题题面并不是很严密啊。。应该说明当石子在走出棋盘边界判定为移除,不然有可能会被理解为不做行动

    分析

    操作次数很大,直接模拟行不通。

    我们想办法将棋盘上所有格子的一次操作转化为矩阵上的变换来解决。

    考虑将棋盘上的格子转化为编号,也就是 \(i\)\(j\) 列的格子编号为 \((i-1)m + j\)。我们建立一个 \(n\times m + 1\)\(1\)​ 列的矩阵,其中最后一行值为 \(1\),其余为 \(0\)

    \[\begin{pmatrix} 0 \\0 \\ \vdots \\ 1 \end{pmatrix} \]

    接下来考虑如何将三种操作对应到矩阵上的操作中:

    下面的步骤是构造变换的矩阵,也就是考虑左乘的矩阵的构造。(记矩阵为 \(op\)

    • 对于第一个操作,假设 \((i, j)\)​ 格子元素 \(+k\)​,记该格编号\(id\),那么 \(op\)\(id\)\(id\) 列应为 \(1\)\(id\)\(nm+1\) 列为 \(k\)
    • 第二个操作,以向南走为例,也就是将 \((i, j)\) (记编号为 \(pre\))的石子移动到 \((i+1, j)\)(记编号为 \(cur\)),那么 \(op\)\(cur\)\(pre\) 列为 \(1\),其余为 \(0\)
    • 第三个操作就是将 \(id\) 行全部设为 \(0\)

    实现

    // Problem: 石头游戏
    // Contest: AcWing
    // URL: https://www.acwing.com/problem/content/208/
    // Memory Limit: 64 MB
    // Time Limit: 1000 ms
    // 
    // Powered by CP Editor (https://cpeditor.org)
    
    #include<bits/stdc++.h>
    using namespace std;
    
    #define debug(x) cerr << #x << ": " << (x) << endl
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define dwn(i,a,b) for(int i=(a);i>=(b);i--)
    #define pb push_back
    #define all(x) (x).begin(), (x).end()
    #define int long long
    
    inline void read(int &x){
        int s=0; x=1;
        char ch=getchar();
        while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
        while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
        x*=s;
    }
    
    struct Mat{
        int n, m;
        vector<vector<int>> w;
    
        Mat(){}
        Mat(int _n, int _m){
            n=_n, m=_m;
            w.resize(n+1, vector<int>(m+1, 0));
        }
        
        void init(int _n, int _m){
        	n=_n, m=_m;
            w.resize(n+1, vector<int>(m+1, 0));
        }
    
        void I(){
        	assert(n==m);
            rep(i,1,n) rep(j,1,n) w[i][j]=(i==j);
        }
    
        Mat operator * (const Mat &o)const{
            assert(m==o.n);
            Mat res(n, o.m);
    
            rep(i,1,n) rep(j,1,o.m){
                int &t=res.w[i][j];
                rep(k,1,o.n) t+=w[i][k]*o.w[k][j];
            }
    
            return res;
        }
    
        Mat fpow(int p){
            Mat res(n, m);
            Mat x=*this;
            res.I();
            for(; p; p>>=1, x=x*x) if(p&1) res=res*x;
            return res;
        }
        
        void solve(){
        	int res=0;
        	rep(i,1,n) rep(j,1,m) res=max(res, w[i][j]);
        	cout<<res<<endl;
        }
        
        void dbg(){
        	rep(i,1,n){
        		rep(j,1,m) cerr<<w[i][j]<<' ';
        		cerr<<endl;
        	}
        	cerr<<endl;
        }
    };
    
    const int N=10;
    
    string ac[15];
    int n, m, t, act;
    int g[N][N];
    int id[N][N];
    
    signed main(){
    	cin>>n>>m>>t>>act;
    	int tot=0;
    	rep(i,1,n) rep(j,1,m){
    		char ch; cin>>ch;
    		g[i][j]=ch-'0'+1;
    		id[i][j]=++tot;
    	}
    	
    	rep(i,1,act){
    		cin>>ac[i];
    		string tmp=ac[i];
    		while(ac[i].size()!=60) ac[i]+=tmp;
    		ac[i]=' '+ac[i];
    	}
    	
    	int nm=n*m;
    	Mat op[65];
    	rep(i,1,60) op[i].init(nm+1, nm+1), op[i].w[nm+1][nm+1]=1;
    	
    	rep(k,1,60){
    		rep(i,1,n) rep(j,1,m){
    			int num=id[i][j];
    			char type=ac[g[i][j]][k];
    			if(isdigit(type)){
    				op[k].w[num][num]=1;
    				op[k].w[num][nm+1]=type-'0';
    			}
    			else if(type!='D'){
    				int pre=num, cur=0;
    				if(type=='N' && i-1) cur=id[i-1][j];
    				if(type=='W' && j-1) cur=id[i][j-1];
    				if(type=='S' && i<n) cur=id[i+1][j];
    				if(type=='E' && j<m) cur=id[i][j+1];
    				if(cur) op[k].w[cur][pre]=1;
    			}
    		}
    	}
    	
    	
    	Mat OP(nm+1, nm+1);
    	OP.I();
    	rep(i,1,60) OP=op[i]*OP;
    	OP=OP.fpow(t/60);
    	
    	Mat res(nm+1, 1); res.w[nm+1][1]=1;
    	res=OP*res;
    	rep(i,1,t%60) res=op[i]*res;
    	
    	res.solve();
    	
    	return 0;
    }
    
  • 相关阅读:
    Linux 之 编译器 gcc/g++参数详解
    linux下history命令显示历史指令记录的使用方法
    Linux 命令之 Navicat 连接 Linux 下的Mysql数据库
    Linux命令
    CentOS 下安装
    CMD命令之 :修改windows的CMD窗口输出编码格式为UTF-8
    CTO、技术总监、首席架构师的区别
    PHP ServerPush (推送) 技术的探讨
    一个公司的管理层级结构
    Table of Contents
  • 原文地址:https://www.cnblogs.com/Tenshi/p/15862045.html
Copyright © 2020-2023  润新知