zoukankan      html  css  js  c++  java
  • 【LOJ】#2550. 「JSOI2018」机器人

    题解

    我不会打表找规律啊QAQ

    规律就是
    对于(n = m)我们每一条左下到右上的对角线上的点的走法都是一样的且每n步一个轮重复
    对于(n != m)我们找到最大公约数(d),在每个(d * d)的方格里满足左上到右下的对角线点的走法一样且d轮一个重复
    然后枚举(dx),(dy = d - dx),我们要满足(gcd(n,dx) == 1)(gcd(m,dy) == 1)这时是一个合法路径
    显然有一些点是必须要经过的,我们把这些点遍历一遍,同时算出(fir[i][j])表示向下走i和向右走j最早第几次走到障碍

    然后我们进行一下dp,就是对于一个点(i,j),要它恰好第k轮撞到障碍物的话,我们需要到达((i,j))之前的点轮数都大于(k),之后的点都大于等于(k)

    然后对于每个(fir[i][j] == k)的点统计一下就好了

    代码

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define pdi pair<db,int>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define MAXN 205
    #define eps 1e-8
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 + c - '0';
    	c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) {
    	out(x / 10);
        }
        putchar('0' + x % 10);
    }
    const int MOD = 998244353;
    int T,N,M,fir[55][55],f[55][55],g[55][55];
    char s[55][55];
    int inc(int a,int b) {
        return a + b >= MOD ? a + b - MOD : a + b;
    }
    int mul(int a,int b) {
        return 1LL * a * b % MOD;
    }
    int gcd(int a,int b) {
        return b == 0 ? a : gcd(b,a % b);
    }
    void Init() {
        read(N);read(M);
        for(int i = 0 ; i < N ; ++i) scanf("%s",s[i]);
    }
    void Solve() {
        int d = gcd(N,M);
        int ans = 0;
        for(int dx = 1 ; dx < d ; ++dx) {
    	int dy = d - dx;
    	if(gcd(N,dx) == 1 && gcd(M,dy) == 1) {
    	    memset(fir,1,sizeof(fir));
    	    int sx = 0,sy = 0,t = 1;
    	    while(1) {
    		for(int i = 0 ; i <= dx ; ++i) {
    		    for(int j = 0 ; j <= dy ; ++j) {
    			if(s[(sx + i) % N][(sy + j) % M] == '1') fir[i][j] = min(fir[i][j],t);
    		    }
    		}
    		++t;
    		sx = (sx + dx) % N;
    		sy = (sy + dy) % M;
    		if(sx == 0 && sy == 0) break;
    	    }
    	    for(int k = 1 ; k <= (N * M) / d ; ++k) {
    		memset(f,0,sizeof(f));memset(g,0,sizeof(g));
    		f[0][0] = 1;g[dx][dy] = 1;
    		for(int i = 0 ; i <= dx ; ++i) {
    		    for(int j = 0 ; j <= dy ; ++j) {
    			if(i && fir[i - 1][j] > k) f[i][j] = inc(f[i][j],f[i - 1][j]);
    			if(j && fir[i][j - 1] > k) f[i][j] = inc(f[i][j],f[i][j - 1]);
    		    }
    		}
    		for(int i = dx ; i >= 0 ; --i) {
    		    for(int j = dy ; j >= 0 ; --j) {
    			if(i <= dx && fir[i + 1][j] >= k) g[i][j] = inc(g[i][j],g[i + 1][j]);
    			if(j <= dy && fir[i][j + 1] >= k) g[i][j] = inc(g[i][j],g[i][j + 1]);
    		    }
    		}
    		for(int i = 0 ; i <= dx ; ++i) {
    		    for(int j = 0 ; j <= dy ; ++j) {
    			if(i + j && fir[i][j] == k) {
    			    ans = inc(ans,mul(mul(f[i][j],g[i][j]),i + j + (k - 1) * d));
    			}
    		    }
    		}
    	    }
    	}
        }
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        read(T);
        while(T--) {
    	Init();
    	Solve();
        }
    }
    
  • 相关阅读:
    网站开发动静分离
    如何前后端分离?
    设置HTML编码为UTF-8
    数据库索引&数据页
    spring中的BeanFactory和FactoryBean的区别与联系
    Java可重入锁与不可重入锁
    abo dto属性验证的坑
    小程序如何去掉button组件的边框
    asp.net core使用gzip
    npm总结
  • 原文地址:https://www.cnblogs.com/ivorysi/p/10019201.html
Copyright © 2011-2022 走看看