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支军队移动后的位置。

 

输入输出样例

输入样例#1:
3 3
0 0
4 -3
6 7
x
m -1 2
y
输出样例#1:
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;
}

极其丑陋的代码

posted @ 2017-09-20 15:48  |斗蜂|  阅读(257)  评论(0编辑  收藏  举报