U149791 正多边形变换

原博客网页——洛谷博客

题目地址

如果您对群论有所了解,那么本题就是对二面体群 \(D_{2n}\) 的简单实现,您可以直接跳到代码部分。下面的解题思路只是对二面体群 \(D_{2n}\) 的构造思路的诠释。

解题思路

(为描述方便,记操作类型为 \(op\) 操作变量为 \(k\) 的操作为 \((op,k)\),连续两次操作记作 \((op,k)*(op',k')\))

  • 对于两次旋转,显然有 \((0,k)*(0,k')=(0,(k+k') \mod n)\)

  • 对于旋转再关于 \(x\) 对称,显然有 \((0,k)*(1,0)=(1,k)\)

  • 对于关于 \(x\) 对称再旋转,发现反转后,顶点标号从逆时针转为顺时针(反之亦然),旋转角度即刻反转,即 \((1,0)*(0,k)=(1,n-k)\)

  • 对于操作 \((1,k)\) ,发现 \(k\) 号轴与 \(x\) 轴的夹角为 \(\frac{\pi k}{n}\) ,且关于 \(k\) 号轴对称相当于旋转 \(\frac{\pi k}{n}\) 弧度、关于 \(x\) 轴对称、再旋转 \(-\frac{\pi k}{n}\) 弧度,于是我们得到恒等式:\((1,k)=(0,\frac{k}{2})*(1,0)*(0,-\frac{k}{2})\) (其中的 \(\frac{k}{2}\) 不一定为整数,这是不太严谨的地方,不过强行把操作变量的范围扩展到半整数也未尝不可)。运用这个等式,推出:

    • \((0,k)*(1,k')=(1,(k+k') \mod n)\)
    • \((1,k)*(0,k')=(1,(k+n-k') \mod n)\)
    • \((1,k)*(1,k')=(0,(k+n-k') \mod n)\)

综上:

  • \((0,k)*(0,k')=(0,(k+k') \mod n)\)
  • \((0,k)*(1,k')=(1,(k+k') \mod n)\)
  • \((1,k)*(0,k')=(1,(k+n-k') \mod n)\)
  • \((1,k)*(1,k')=(0,(k+n-k') \mod n)\)

我们可以将正多边形的初始状态记作 \((0,0)\) ,那么代码就是对以上四个式子的实现,时间复杂度 \(O(m)\)

代码\(_{_{{\text{(数据就是它造的)}}}}\)

#include<cstdio>
using namespace std;
int main() {
	int n, m;
	int reflect = 0, rotate = 0;
	scanf("%d%d", &n, &m);
	while (m--) {
		int op, k;
		scanf("%d%d", &op, &k);
		if (reflect) rotate = (rotate + n - k) % n;
		else rotate = (rotate + k) % n;
		reflect = (reflect + op) % 2;
	}
	printf("%d %d", reflect, rotate);
	return 0;
}
posted @ 2021-02-05 15:08  Square_Circle  阅读(68)  评论(0)    收藏  举报