模拟赛碰到的题,来写一发。
关于循环节问题肯定是要找最小循环节,而二维矩形明显能拆成两个一维问题,最后乘起来即可,下面以行为例。
然后考虑循环节一定是 \(n\) 的因子,于是对于一个质因数 \(p\),每次考虑检验前 \(\frac{n}{p^x}\) 个中,按照 \(\frac{n}{p^{x+1}}\) 分成的 \(p\) 块是否相等,不相等时即可知道最小循环节有多少个 \(p\)。
检验的话考虑倍增,每次询问 \([1,2^i]\) 块和 \([2^i+1,2^{i+1}]\) 块是否相等,最后一点单独处理。
总次数为 \(\sum k_i \times \log p_i= \sum \log p_i^{k_i}= \log n\)。
int simons(int a, int b, int c, int d, int e, int f) {cout << "? " << a << ' ' << b << ' ' << c << ' ' << d << ' ' << e << ' ' << f << endl;int w;cin >> w;return w;
}int truth(int n, int m) {auto div = [&](int x) {vector < pair <int, int> > p;for (int i = 2; i <= x; i++) {if (x % i == 0) {int c = 0;while (x % i == 0) x /= i, c++;p.emplace_back(i, c);}}return p;};auto p = div(n);int nres = 1;for (auto [x, c] : p) {int lst = n, cc = 0;for (int i = 1; i <= c; i++) {int nw = lst / x;auto chk = [&](int r) -> bool {int lst = 0;for (int i = 1; i * 2 <= x; i *= 2) {if (!simons(i * r, m, 1, 1, i * r + 1, 1)) return 0;lst = i * 2;}lst = x - lst;if (!lst) return 1;return simons(lst * r, m, 1, 1, r * x - lst * r + 1, 1);};if (!chk(nw)) break;lst /= x;cc++;}nres *= pow(x, c - cc);}p = div(m);int mres = 1;for (auto [x, c] : p) {int lst = m, cc = 0;for (int i = 1; i <= c; i++) {int nw = lst / x;auto chk = [&](int r) -> bool {int lst = 0;for (int i = 1; i * 2 <= x; i *= 2) {if (!simons(n, i * r, 1, 1, 1, i * r + 1)) return 0;lst = i * 2;}lst = x - lst;if (!lst) return 1;return simons(n, lst * r, 1, 1, 1, r * x - lst * r + 1);};if (!chk(nw)) break;lst /= x;cc++;}mres *= pow(x, c - cc);}nres = n / nres, mres = m / mres;// debug(nres, mres);auto cal = [&](int x) {int cc = 0;for (int i = 1; i <= x; i++) {if (x % i == 0) cc++;}return cc;};return cal(nres) * cal(mres);
}