第一章见博客Timmylyx。
欢迎来到第二章,谢谢支持。
本章题目:平面向量表达式。
题面:
平面向量(a,b)的相关运算定义如下:
-
加法:(a1,b1)+(a2,b2)=(a1+a2,b1+b2)
-
减法:(a1,b1)−(a2,b2)=(a1−a2,b1−b2)
-
数乘:k×(a,b)=(a,b)×k=(ka,kb)
-
点乘:(a1,b1)⋅(a2,b2)=a1a2+b1b2
本题不考虑向量叉乘这种运算。
因此两个向量相加减,结果仍然是向量;数字和向量相乘,结果是一个向量;向量和向量相乘,结果是一个数。
向量加减和数值加减的优先级相同;向量数乘、向量点乘和数值乘法的优先级相同。
原方法:栈
最经典的表达式求值应用,注意处理向量也需要用到栈。
其他的就不多说了,看代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
struct node{
int a[2],type;
};
stack <node> num;
stack <char> op;
stack <int> xl;
node now,nowx;
node kk=node{{0,0},0};
const int m=1000000007;
void out(node ans){
if (ans.type==0){
while (ans.a[0]<0) ans.a[0]+=m;
cout<<ans.a[0];
}
else{
while (ans.a[0]<0) ans.a[0]+=m;
while (ans.a[1]<0) ans.a[1]+=m;
cout<<'('<<ans.a[0]<<','<<ans.a[1]<<')';
}
}
void ceil(char c){
//计算乘法
if (op.empty()) return ;
if (op.top()=='*'){
op.pop();
node n1=num.top(); num.pop();//取出数(向量)
node n2=num.top(); num.pop();
if (n1.type==0) {
if (n2.type==0){
num.push(node{{n1.a[0]*n2.a[0]%m,0LL},0LL});//都是数
}
else{
num.push(node{{n1.a[0]*n2.a[0]%m,n1.a[0]*n2.a[1]%m},1LL});//都是n2是向量
}
}
else{
if (n2.type==0){
num.push(node{{n1.a[0]*n2.a[0]%m,n1.a[1]*n2.a[0]%m},1LL});//n1是向量
}
else{
num.push(node{{(n1.a[0]*n2.a[0]+n1.a[1]*n2.a[1])%m,0LL},0LL});//全是向量
}
}
ceil(c);
}
else if (c!='*'&&op.top()!='('&&op.top()!=',') {
node n2=num.top(); num.pop();//取出数(向量)
node n1=num.top(); num.pop();
if (op.top()=='+') {
num.push(node{{(n1.a[0]+n2.a[0])%m,(n1.a[1]+n2.a[1])%m},n1.type});//只可能是加减
}
if (op.top()=='-'){
num.push(node{{(n1.a[0]-n2.a[0])%m,(n1.a[1]-n2.a[1])%m},n1.type});
}
op.pop();ceil(c);
}
else return ;
}
void go(){
while (!op.empty()&&op.top()!='('&&op.top()!=','){//寻找向量符号/左括号
ceil('+');
}
if (op.empty()) return ;
if (op.top()==','){
int tmp=xl.top(); xl.pop();
node tmpx=num.top(); num.pop();
num.push(node{{tmp,tmpx.a[0]},1LL});//保存向量的第二个值
}
op.pop();
}
signed main(){
string s;
cin>>s;s+=")";
for (int i=0; i<s.size(); i++){
char c=s[i];
if (c>='0'&&c<='9') {
now.a[0]=(now.a[0]*10+c-'0')%m;//计入数字
}
else if (c=='+'||c=='-'||c=='*'){
if (s[i-1]>='0'&&s[i-1]<='9') {
num.push(now); now=kk;//重置数字
}
ceil(c);
op.push(c);//计算
}
else if (c=='('){//计入左括号
op.push('(');
}
else if (c==','){//向量符号
if (s[i-1]>='0'&&s[i-1]<='9') {
num.push(now); now=kk;//重置数字
}
go(); op.push(',');
xl.push(num.top().a[0]);//保存第一个向量元素
num.pop();
}
else{
if (s[i-1]>='0'&&s[i-1]<='9') {
num.push(now); now=kk;//重置数字
}
go();
}
}
node ans=num.top();
out(ans);
return 0;
}
破解:函数调用
由于前面的代码过于冗长,本蒟蒻实在想优化一下
于是,我想到了使用函数!(函数不就是栈吗?!)
这里设四个函数:
xl():求一个向量的函数。
我们可以先获取一个多项式(见后),然后分两种情况:
-
如果遇到
,
真向量,在获取一个多项式拼接成向量。 -
否则,假向量,直接返回多项式的值。
expr():求一个多项式的函数。
我们就连续获得多个单项式(见后)加(减)起来。
term():求一个单项式的函数。
我们就连续获得多个常数(见后)乘起来。
factor():求一个常数的函数。
分两种情况:
-
是数字:获取完整这个数并返回。
-
是
(
:获取一个向量并跳过括号。
最后输出 expr() 即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1000000007;
string s; int id=0;
struct node{
int x,y,type;
};
node factor();
node term(){
node ans=factor();
while (s[id]=='*'){
id++; node tmp=factor();
if (tmp.type==0&&ans.type==0) ans.x=ans.x*tmp.x%mod;
else if (tmp.type==1&&ans.type==1){
ans.type=0; ans.x=(ans.x*tmp.x%mod+ans.y*tmp.y%mod)%mod;
}
else if (tmp.type==1&&ans.type==0){
ans.type=1; ans.y=ans.x*tmp.y%mod; ans.x=ans.x*tmp.x%mod;
}
else{
ans.x=ans.x*tmp.x%mod; ans.y=ans.y*tmp.x%mod;
}
}
return ans;
}
node expr(){
node ans=term();
while (s[id]=='+'||s[id]=='-'){
if(s[id]=='+'){
id++; node tmp=term();
ans.x+=tmp.x;
ans.y+=tmp.y;
ans.x%=mod;
ans.y%=mod;
}
else if (s[id]=='-'){
id++; node tmp=term();
ans.x-=tmp.x-3000000021LL;
ans.y-=tmp.y-3000000021LL;
ans.x%=mod;
ans.y%=mod;
}
}
return ans;
}
node xl(){
node calc = expr();
if (s[id]==',') {
id++; calc.y = expr().x; calc.type=1;
}
return calc;
}
node factor(){
node ans=node{0,0,0};
if (s[id]=='('){
id++; ans=xl(); id++;
}
else {
while (s[id]<='9'&&s[id]>='0'){
ans.x=ans.x*10+s[id]-'0'; id++;
}
}
return ans;
}
signed main(){
cin>>s;
node tmp=expr();
if (tmp.type==0) cout<<tmp.x;
else cout<<"("<<tmp.x<<","<<tmp.y<<")";
return 0;
}