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 }

 

好奇妙。做的时候我还想暴力模拟。但是点太多会超时。也想过用一个点来代表整体,然后更新其他点和这个点的关系。但是对称旋转变化下关系变化没有可循之处。后来同学和我说可以用操作前缀和。学到了。

posted @ 2021-04-14 18:54  反射狐  阅读(94)  评论(0编辑  收藏  举报