L国的战斗续之多路出击(洛谷P2129)——基础的矩阵乘法
题目背景
广而告之:背景见其他L国的战斗!!大家一起刷
题目描述
这一次,L国决定军队分成n组,分布在各地,若以L国为原点,可以看作在一个直角坐标系内。但是他们都受统一的指挥,指令部共发出m个命令。命令有移动、上下转移和左右转移(瞬移??),但是由于某些奇奇怪怪的原因,军队收到命令总是有延迟,为了方便,军方已经写好一个栈(那还要我干嘛,自己都写好不就行了?),所以你要处理的顺序,应该是从后往前。
输入输出格式
输入格式:
输入文件army.in包括n+m+1行
第一行两个整数n、m
接下来n行
第i行有两个整数xi yi表示第i支军队的位置。
又是m行
每行首先是一个字符 C
若C为m 则紧跟两个整数 p q 表示把每支军队的位置从(xi,yi)移到(xi+p.yi+q)
若C为x 则表示把每支军队的位置从(xi,yi)移到(-xi,yi)
若C为y 则表示把每支军队的位置从(xi,yi)移到(xi,-yi)
输出格式:
输出文件army.out包含n行
第i行有两个整数xi、yi,表示第i支军队移动后的位置。
输入输出样例
3 3 0 0 4 -3 6 7 x m -1 2 y
1 2 -3 5 -5 -5
说明
对于30%的数据 1≤n≤1000 1≤m≤1000
对于100%的数据 1≤n≤500000 1≤m≤500000 Ai在longint范围内
———————————分割线———————————
终于……我还是写了一道矩阵的例题。废话不多说先来讲题吧。
首先我们可以将每一个点变成一个矩阵。
然后,这样子就是m的操作。
这样子就是x的操作。
同理这样就是y的操作。
所以!我们可以先将所有的操作先乘起来,最后得到一个矩阵和每一个点乘就可以了!
这样的话(这个话字我不知道打了几遍……每次都是跳出来haunted……)复杂度就能大大减少!
最后题目中倒序给出操作是为了方便我们计算!不用反过来的!设点的矩阵是A,操作(正序)分别有B,C,D。则乘的顺序一定是D*(C*(B*A))。所以结合律一用就是(D*C*B)*A。所以就不用反过来了!(之前被这个坑了很久……真的是智商捉急)。
#include<bits/stdc++.h> using namespace std; struct nob{ long long mat[4][4]; friend nob operator * (const nob &a,const nob &b){ nob rem; for (int i=1; i<=3; i++){ for (int l=1; l<=3; l++){ long long sum=0; for (int k=1; k<=3; k++){ sum+=a.mat[i][k]*b.mat[k][l]; } rem.mat[i][l]=sum; } } return rem; } }move[500005],ans; struct point{ long long mat[4][2]; friend point operator * (const point &a,const nob b){ point rem; for (int i=1; i<=3; i++){ long long sum=0; for (int k=1; k<=3; k++){ sum+=a.mat[k][1]*b.mat[i][k]; } rem.mat[i][1]=sum; } return rem; } }a[500005]; struct oper{ char ch; long long x,y; }b[500005]; int n,m; nob add(long long aa,long long bb){ nob x; x.mat[1][1]=1;x.mat[1][2]=0;x.mat[1][3]=aa; x.mat[2][1]=0;x.mat[2][2]=1;x.mat[2][3]=bb; x.mat[3][1]=0;x.mat[3][2]=0;x.mat[3][3]=1; return x; } nob turn_x(){ nob x; x.mat[1][1]=-1;x.mat[1][2]=0;x.mat[1][3]=0; x.mat[2][1]=0;x.mat[2][2]=1;x.mat[2][3]=0; x.mat[3][1]=0;x.mat[3][2]=0;x.mat[3][3]=1; return x; } nob turn_y(){ nob x; x.mat[1][1]=1;x.mat[1][2]=0;x.mat[1][3]=0; x.mat[2][1]=0;x.mat[2][2]=-1;x.mat[2][3]=0; x.mat[3][1]=0;x.mat[3][2]=0;x.mat[3][3]=1; return x; } int main(){ for (int i=1; i<=3; i++){ for (int l=1; l<=3; l++){ if (i!=l) ans.mat[i][l]=0; else ans.mat[i][l]=1; } } cin>>n>>m; for (int i=1; i<=n; i++){ cin>>a[i].mat[1][1]>>a[i].mat[2][1]; a[i].mat[3][1]=1; } for (int i=1; i<=m; i++){ cin>>b[i].ch; if (b[i].ch=='m') cin>>b[i].x>>b[i].y; } for (int i=1; i<=m; i++){ nob op; if (b[i].ch=='x') op=turn_x(); else if (b[i].ch=='y') op=turn_y(); else op=add(b[i].x,b[i].y); ans=ans*op; } for (int i=1; i<=n; i++){ a[i]=a[i]*ans; cout<<a[i].mat[1][1]<<" "<<a[i].mat[2][1]<<endl; } return 0; }
极其丑陋的代码