传送门: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个点构成一个集合,且同一集合内的点是等价的
的位置,发现因为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;
}