CodeForces-492E Vanya and Field(思维题/最小公倍数)

传送门:http://codeforces.com/problemset/problem/492/E

题意:有一个n*n的矩阵,在矩阵中有m颗苹果树,一个人移动的单位向量为(dx,dy),且dx,dy与n互质,每次移动后的位置是((x+dx)%n,(y+dy)%n),当走到一个走过的点时停止,

问起点在哪个点时,走过的苹果树最多


题解:首先最重要的条件就是gcd(n,dx)=gcd(n,dy)=1;由这可知x方向上的位移与n互质,于是当沿着dx方向走n次恰好回到起点

(最小公倍数),并且走过的n个点互不重合,这个可以通过自己枚举验证,y方向上的同理.

于是同时考虑x,y时,一定能从(x0,y0)走n步再次回到(x0,y0),且可以经过每行每列,于是我们可以将(0,y0)设为起点,于是每个

起点就与其他n-1个点构成一个集合,且同一集合内的点是等价的


现在假设(0,0)为起点,那么第一步后就到达了(dx%n,dy%n),第k步后到达了(k*dx%n,k*dy%n),对于每一步我们可以储存他到达
的位置,发现因为x,y都是互异的,因此只需要x[k*dx%n]=k*dy%n;这样关联,就能表示一个点的坐标(k*dx%n,k*dy%n)

那么对于(0,y0)为起点,我们第k步就到达了(k*dx%n,(y0+k*dy)%n),于是可以发现对于每一个位置,因为起点x==0,

我们只要找到y=x[k*dx%n],就得到y0=y-y[k],对应的cnt[y0]++,最后找到最大的cnt[y0]输出y0

#include<cstdio>
#include<algorithm>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn = 1e6 + 5;
int n, m, dx, dy, x[maxn], cnt[maxn];
int main() {
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d%d%d", &n, &m, &dx, &dy)) {
        memset(cnt, 0, sizeof(cnt));
        memset(x, 0, sizeof(x));
        int x1 = 0, y1 = 0;
        for(int i = 1; i <= n; i++) {
            x1 = (x1 + dx) % n; y1 = (y1 + dy) % n;
            x[x1] = y1;
        }
        for(int i = 0; i < m; i++) {
            scanf("%d%d", &x1, &y1);
            int y0 = (y1 - x[x1] + n) % n;
            cnt[y0]++;
        }
        int index = 0;
        for(int i = 1; i < n; i++) {
            // printf("%d%c",cnt[i],i==n-1?'\n':' ');
            if(cnt[i] > cnt[index])index = i;
        }
        printf("0 %d\n", index);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值