平面向量表达式

第一章见博客Timmylyx。

欢迎来到第二章,谢谢支持。

本章题目:平面向量表达式

题面:

平面向量(a,b)的相关运算定义如下:

  1. 加法:(a1​,b1​)+(a2​,b2​)=(a1​+a2​,b1​+b2​)

  2. 减法:(a1​,b1​)−(a2​,b2​)=(a1​−a2​,b1​−b2​)

  3. 数乘:k×(a,b)=(a,b)×k=(ka,kb)

  4. 点乘:(a1​,b1​)⋅(a2​,b2​)=a1​a2​+b1​b2​

本题不考虑向量叉乘这种运算。

因此两个向量相加减,结果仍然是向量;数字和向量相乘,结果是一个向量;向量和向量相乘,结果是一个数。

向量加减和数值加减的优先级相同;向量数乘、向量点乘和数值乘法的优先级相同。

原方法:栈

最经典的表达式求值应用,注意处理向量也需要用到栈。

其他的就不多说了,看代码:

​
#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;
} 

​

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值