Rotate and Flip - 操作前缀和
题目:https://vjudge.net/contest/433343#problem/B
大意:给出N个点和M个对于所有点操作。操作有4种:1顺时针旋转90度;2逆时针旋转90度;3对于x=p对称;4对于y=p对称。有Q个询问,问操作a结束后b点的坐标。
思路:把每个点的坐标看成未知数a1x+b1y+c1和a2x+b2y+c2,每种操作后其坐标会发生变化。可以用ax+by+c来表示。
1 #include <stdio.h> 2 using namespace std; 3 typedef long long ll; 4 const ll mx=2e5+10; 5 ll N, M, Q; 6 struct node{ 7 ll x, y; 8 }nos[mx]; 9 struct relation{ 10 ll a, b, c; 11 void same(relation r){ 12 a=r.a, b=r.b, c=r.c; 13 } 14 void fusame(relation r){ 15 a=-r.a, b=-r.b, c=-r.c; 16 } 17 }x[mx], y[mx]; 18 void solve(){ 19 scanf("%lld", &N); 20 for(ll i=1;i<=N;i++)scanf("%lld %lld", &nos[i].x, &nos[i].y); 21 scanf("%lld", &M); 22 x[0].a=1, x[0].b=0, x[0].c=0; 23 y[0].a=0, y[0].b=1, y[0].c=0; 24 ll op, p; 25 for(ll i=1;i<=M;i++){ 26 scanf("%lld", &op); 27 if(op==1){ 28 x[i].same(y[i-1]); 29 y[i].fusame(x[i-1]); 30 } 31 else if(op==2){ 32 x[i].fusame(y[i-1]); 33 y[i].same(x[i-1]); 34 } 35 else if(op==3){ 36 scanf("%lld", &p); 37 x[i].fusame(x[i-1]);x[i].c+=2*p; 38 y[i].same(y[i-1]); 39 } 40 else if(op==4){ 41 scanf("%lld", &p); 42 x[i].same(x[i-1]); 43 y[i].fusame(y[i-1]);y[i].c+=2*p; 44 } 45 } 46 scanf("%lld", &Q); 47 for(ll i=1;i<=Q;i++){ 48 ll a, b, xx, yy;//a是操作数 b是点 49 scanf("%lld %lld", &a, &b); 50 xx=x[a].a*nos[b].x+x[a].b*nos[b].y+x[a].c; 51 yy=y[a].a*nos[b].x+y[a].b*nos[b].y+y[a].c; 52 printf("%lld %lld\n", xx, yy); 53 } 54 } 55 int main(){ 56 solve(); 57 return 0; 58 }
好奇妙。做的时候我还想暴力模拟。但是点太多会超时。也想过用一个点来代表整体,然后更新其他点和这个点的关系。但是对称旋转变化下关系变化没有可循之处。后来同学和我说可以用操作前缀和。学到了。