• 【数学(矩阵加速)】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;
    }
    
  • 相关阅读:
    用python一键爬取几千张表情包斗图,分分钟征服朋友圈所有好友
    Python新手必备的15个字符串方法,你学废了吗?
    价值10K+的Python面试题,珍藏已久,分享给大家!
    用python开发一个益智游戏,没事就锻炼锻炼自己的方向感
    室友吃个泡面的时间,我就用Python代码下载了几千张手机壁纸,简直yyds!
    Python GUI编程:tkinter 关于 ttkbootstrap 的使用
    .NET 6 使用 System.Drawing.Common 出现 The type initializer for ‘Gdip’ threw an exception 异常的解决办法
    如何在 Linux 上使用 NPOI
    Silverlight企业应用快速开发平台框架设计(二)分析平台实现重点是什么,要怎么做?
    Silverlight企业应用快速开发平台框架设计(一)目标
  • 原文地址:https://www.cnblogs.com/Tenshi/p/15862045.html
Copyright © 2020-2023  润新知