http://codeforces.com/contest/758/problem/C
需要一个能够找到任意一个位置的步数的方法,就能解决三个问题。
预处理出one(row, col)表示第一次经过这个点,需要的步数。
sec(row, col),thr(row, col)分别是第二、三步。
那么,循环节就会产生,记录步数为X, Y, Z,那么,第一二步的差距,和第二三步的差距,分别代表了从下走上去和从上走下来。
那么第4次,就会和第一二步的差距相等
就比如是5、17、23,那么下一步就是35.
但是预处理这个onesec hr也特别多细节。
然后就可以用循环节了,5 + 每18个增加两次,还要特判下剩余的再够一次。

#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> #include <bitset> int n, m, x, y; LL tk; int one(int row, int col) { return (row - 1) * m + col; } int sec(int row, int col) { if (row == n) { return n * m + (n - 1) * m + col + (max(0, n - 2) * m); } else if (row == 1) { return n * m + max(0, (n - 2)) * m + col; } return one(row, col) + m - col + (n - row) * m + max((n - 1 - row), 0) * m + col; } int thr(int row, int col) { if (row == 1) { if (n == 1) { return m * 2 + col; } return n * m + (n - 1) * m * 2 + m * (max(0, n - 2)) + col; } else if (row == n) { return n * m + (n - 1) * m * 3 + max(0, (n - 2)) * m + col; } return sec(row, col) + (row - 1) * m + (row - 2) * m + m; } LL tofind(int row, int col) { LL k = tk; if (k <= one(row, col)) return k >= one(row, col); k -= one(row, col); int cir = thr(row, col) - one(row, col); LL ans = 1LL + (k / cir) * 2; ans += k % cir >= sec(row, col) - one(row, col); return ans; } void work() { cin >> n >> m >> tk >> x >> y; // cout << one(x, y) << " " << sec(x, y) << " " << thr(x, y) << endl; LL ansmx = -1, ansmi = 1e18L; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { ansmx = max(ansmx, tofind(i, j)); ansmi = min(ansmi, tofind(i, j)); } } cout << ansmx << " " << ansmi << " " << tofind(x, y) << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }