题意: 给定一个长度为 n的坐标序列 a,以及一个坐标 M0。 Mi和 Mi−1以 a{(i−1)mod n}对称,求 Mj坐标
题解: 我们先写几项出来:
① M1= 2∗a0−M0
② M2=2∗a1−M1=2∗a1−2∗a0+M0
③ M3=2∗a2−M2=2∗a2−2∗a1+2∗a0−M0
④ M4=2∗a3−M3=2∗a3−2∗a2+2∗a1−2∗a0+M0
⑤ M5=2∗a4−M4=2∗a4−2∗a3+2∗a2−2∗a1+2∗a0−M0
这里可以看出来是有前缀和的思想,处理的是一加一减的前缀。
即 pre[0]=a[0],pre[1]=a[0]−a[1],pre[2]=a[0]−a[1]+a[2],以此类推。
由于有取模的影响,那么先求处理出有多少完整的前缀 n,
同时 n是奇数,故连续的 n个元素最多只能存在一组,其他都会相互抵消。
故我们只需处理三部分:
1. 连续的前缀部分为 2∗k个,那么无需计算,连续的前缀为 2∗k+1个,那么只需统计一个即可。
2. 除去连续的前缀部分, a元素的部分。
3.M0
处理的时候要注意存储的是加 a0,减 a1,即加 a偶数,减 a奇数。
所以需要计算一下位置来确定当前是否需要加负号。
代码:
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef long long ll;
typedef pair<ll, ll> PLL;
const int N = 1e5 + 10;
PLL a[N], all[N], M;
ll n, j;
int main()
{
scanf("%lld%lld", &n, &j);
scanf("%lld%lld", &M.x, &M.y);
for(int i = 0; i < n; i++) scanf("%lld%lld", &a[i].x, &a[i].y);
all[0] = a[0];
for(int i = 1; i < n; i++) {
if(i & 1) all[i].x = all[i - 1].x - a[i].x, all[i].y = all[i - 1].y - a[i].y;
else all[i].x = all[i - 1].x + a[i].x, all[i].y = all[i - 1].y + a[i].y;
}
int cnt = ((j / n) & 1);
int t = (j - 1) % n;
int pM = (j & 1) ? -1 : 1;
int pS = (t & 1) ? -1 : 1;
int pF = -pS;
if(j % n == 0) pS = 0, pF = 1;
ll rx = pM * M.x + 2ll * (cnt * pF * all[n - 1].x + pS * all[t].x);
ll ry = pM * M.y + 2ll * (cnt * pF * all[n - 1].y + pS * all[t].y);
printf("%lld %lld\n", rx, ry);
return 0;
}