CSP-31补题日记--梯度求解

news2024/11/25 2:56:55

202309-3-梯度求解

题目链接

http://118.190.20.162/view.page?gpid=T173

最近刚刚在上数据结构二叉树
跟这道题真的是强相关
然后在就是涉及到了数学求导
这基本上是我复学两个月做的最久的题了
感觉做完这道题对栈和二叉树理解比以前清晰了很多
不摆了
上代码

** 题目思路:
题意是给我们一个后缀表达式
显然,我们就可以写出这个表达式
那么怎么来实现求导呢?
不妨讨论,常数求导equal 0;
偏导的未知数求导equal 1 ;
其他符号 a (±)b求导equal
a导 (±
)b导
这样我们是不是就可以递归实现求导呢!
分析可得做题步骤
1:利用栈来建立二叉树存表达式,因为是后缀表示,所以唯一可以考虑只使用一个栈
2:dfs遍历求导,并将结果存在二叉树里面
3:带入计算,最重要的是要取模运算(可恶)
**

/*
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
typedef  pair<int,int> pi ;
#define if1(x) for(int i =1 ;i<=x;i++)
#define if0(x) for(int i = 0;i<x;i++)
#define jf0(x) for(int j = 0;j<x;j++)
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int m,n,idx;
struct node{
   int vis_num;//1表示他是数字,0表示他是未知数,
   //2表示他是操作符号,3表示求偏导的未知数
   int x;
   ll val;
   char op;
   //既然要存树,那么不妨使用数组来存树
   int fa;
   int l;
   int r;
   int myself;
};
node tree[550];
//vector<node> tree;
vector<int> xs(200);
int xans;//存储偏导未知数的位置
string s;
node retu0,retux,retu1;
stack<node> sta_num;
void push_num(string x){
   int num = stoi(x);
   node te = *new(node);
   te.vis_num=1;te.val =num;
   te.fa = te.l = te.r =-1;
   tree[idx] = te;
   te.myself = idx++;
   // tree.push_back(te)
   sta_num.push(te);

}
node dfs(node root){
//分析讨论vis的三种状态
//当节点未数字时,求导直接返回0;
   if(root.vis_num==1) return retu0;//数字求导的结果就是0

//当节点遇到x时,求导时应该分两种情况判断
   else if(root.vis_num==0){
//若x是我们所求的偏导,我们就应该返回retux
       if(root.x==xans) return retu1;   
//若x不是是我们所求未知数的偏导,
//则我们应该视为常数我们就应该返回0
       else return retu0;
   }

//ok写到这里,应该是此代码最复杂的一部分
//(a*b)求导=a导*b+b导*a
   else if(root.op=='*'){
       //注意,我们还应该给新分配的三个节点一个idx来存下来
       node rnode = *new(node);
       node lnode = *new(node);
       node father = *new(node);
       // tree.push_back(rnode);
       // tree.push_back(lnode);
       // tree.push_back(father);
       //先写一下左边巴
       lnode.vis_num=2;
       lnode.op = '*';
       lnode.l = root.l;
       lnode.r = dfs(tree[root.r]).myself;
       lnode.fa = father.myself;
       tree[idx]  = lnode;
       lnode.myself = idx++;
       


       //写右边
       rnode.vis_num = 2;
       rnode.op='*';
       rnode.r = root.r;
       rnode.l = dfs(tree[root.l]).myself;
       rnode.fa = father.myself;

       tree[idx] = rnode;
       rnode.myself = idx++;
       
       //写她爹
       father.vis_num = 2;
       father.op = '+';
       father.r = rnode.myself;
       father.l = lnode.myself;
       tree[idx] = father;
       father.myself = idx++;
       return father;



   }
   //op是+-的时候,很明显就是l导+-r导
   else{
       node father = *new(node);
       father.fa = father.l = father.r = -1;
       father.vis_num=2;
       father.op = root.op;
       father.r = dfs(tree[root.r]).myself;
       father.l = dfs(tree[root.l]).myself;
       father.myself = idx;
       tree[idx++] = father;
       return father;
   }
}
void init(){
   retu0.fa = retu0.l=retu0.r=-1;
   retu0.vis_num=1;
   retu0.val=0;
   retu0.myself = -2;//特殊给0;

   retu1.fa = retu1.r=retu1.l=-1;
   retu1.vis_num=1;//特殊给一个。
   retu1.val = 1;
   retu1.myself=-4;

   retux.fa = retux.l = retux.r=-1;
   retux.vis_num = 3;
   retux.myself = -3;//特殊给未知数的下标;
   return;
}
ll caculate(node root){
   if(root.vis_num==1)return root.val;
   //遇到计算偏导x时
   else if(root.vis_num==3)return xs[xans];
   //通过处理,我们可以肯定dfs后再无vis——num=0,就是未知数的情况了
   //写在后面,根本特殊处理不了一点点
   //因为它有些是在*+-里面的未知数
   else if(root.vis_num==0) return xs[root.x];
   else{
       //现在就是开始运算了,
       ll a , b ;
       if(root.l<0){
           if(root.l == -2) a=0;
           else if(root.l == -3) a = xs[xans];
           else if(root.l==-4) a = 1;
       }
       else a = caculate(tree[root.l]);
       if(root.r<0){
           if(root.r == -2) b=0;
           else if(root.r == -3) b = xs[xans];
           else if(root.r== -4) b = 1;
       }
       else b = caculate(tree[root.r]);

       if(root.op=='+'){
           return ((a%mod)+(b%mod))%mod;
       }else if(root.op=='-'){
           return ((a%mod)-(b%mod))%mod;
       }
       else{
           return (a%mod)*(b%mod)%mod;
       }
   }
}
void solve(){
   init();
   cin>>n>>m;//n-自变量,m-求偏导的次数
   getchar();
   getline(cin,s);
   int le = s.size();
   if0(le){

       //split 操作
       int j = i+1;
       while(s[j]!=' '&&j<le)j++;
       string temp = s.substr(i,j-i);

       //为数字
       if((temp[0]>='0'&&temp[0]<='9')||temp[0]=='-'&&j>i+1){
           push_num(temp);
       }

       //为未知数的时候
       else if(temp[0]=='x'){
           int te = stoi(temp.substr(1,temp.size()-1));
           node tt = *new(node);
           tt.vis_num=0;tt.x=te;
           tt.fa = tt.l = tt.r =-1;
           tree[idx]=tt;
           tt.myself = idx++;
           //tree.push_back(tt);
           sta_num.push(tt);
       }


       else {
           //通过简单分析哈,我们在遇到操作符号的时候可以更新
           //一下树,不如直接存树?
           node te = *new(node);
           te.vis_num=2;
           te.op = temp[0];
           te.fa =-1;
           te.r = sta_num.top().myself;
           sta_num.pop();
           te.l = sta_num.top().myself;
           sta_num.pop();
           tree[idx] = te;
           te.myself = idx++;
           sta_num.push(te);

       }
       
       i=j;//1st--bug,因为for它自己已经加一辣
   }

   //存树结束
   if0(m){
       int temp_idx = idx;//考虑后面我们可以释放一波内存
       //既然写的这么认真了,那么在内存方面也可以考虑变得更优。
       cin>>xans;//读入偏导x
       jf0(n)cin>>xs[j+1];//读入x的赋值,因为我们在建树的时候
       //我们直接存的是x的下标,所以未便于调用,从1开始存。
       //简单讨论,最后栈的唯一元素便是根节点。
       node ans = dfs(sta_num.top());
       ll res = caculate(ans)%mod;
       res = (res+mod)%mod;
       cout<<res<<endl;
       idx = temp_idx;
   }

}
int main(){
   solve();
  // getchar();
   
   return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1170830.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

动态规划算法学习——解码方法

一&#xff0c;题目 一条包含字母 A-Z 的消息通过以下映射进行了 编码 &#xff1a; A -> "1" B -> "2" ... Z -> "26" 要 解码 已编码的消息&#xff0c;所有数字必须基于上述映射的方法&#xff0c;反向映射回字母&#xff08;可能有…

【C++】:类和对象(中):const成员 || 取地址及const取地址操作符重载

&#x1f4ea;1.const成员 &#x1f4ea;将const修饰的“成员函数”称之为const成员函数&#xff0c;const修饰类成员函数&#xff0c;实际修饰该成员函数隐含的this指针&#xff0c;表明在该成员函数中不能对类的任何成员进行修改 &#x1f388;首先我们来想一想为什么在C中…

421. 数组中两个数的最大异或值 (中等,位运算)

题目越短越难啊 关键在于要明白如果我们已经知道有一些组合进行异或运算能得到最高位为1的结果&#xff0c;那么最终答案必定在这些组合之中其次异或运算有个性质&#xff0c;ab XOR c 等价于 ba XOR c&#xff0c;因此对于第 k 位能否取到 1 的情况&#xff0c;我们只需要用 …

349.两个数组的交集+350.两个数组的交集II(set/multiset)

目录 一、349.两个数组的交集 二、350.两个数组的交集II 一、349.两个数组的交集 349. 两个数组的交集 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {//…

Redis中Hash类型的命令

目录 哈希类型的命令 hset hget hexists hdel hkeys hvals hgetall hmget hlen hsetnx hincrby hincrbyfloat 内部编码 Hash类型的应用场景 作为缓存 哈希类型和关系型数据库的两点不同之处 缓存方式对比 Redis自身已经是键值对的结构了,Redis自身的键值对就…

【论文笔记】Point Cloud Forecasting as a Proxy for 4D Occupancy Forecasting

原文链接&#xff1a;https://arxiv.org/abs/2302.13130 1. 引言 运动规划需要预测其余物体的运动&#xff0c;但相应的感知模块如建图、目标检测、跟踪和轨迹预测通常都需要大量人力标注HD地图、语义标签、边界框或物体的轨迹&#xff0c;难以扩展到大型无标签数据集上。3D点…

Linux文本编辑器vim使用和配置详解

vim介绍 ​ vim是Linux的一款文本编辑器&#xff0c;可以用来编辑代码&#xff0c;而且支持语法高亮&#xff0c;还可以进行一系列配置使vim更多样化。也可以运行于windows&#xff0c;mac os上。 ​ vim有多种模式&#xff0c;但目前我们只介绍绝大多数场景用的到的模式&…

CCF CSP认证 历年题目自练Day43

题目一 试题编号&#xff1a; 201604-3 试题名称&#xff1a; 路径解析 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 256.0MB 问题描述&#xff1a; 问题描述   在操作系统中&#xff0c;数据通常以文件的形式存储在文件系统中。文件系统一般采用层次化的组织形式&…

NLP之Bert多分类实现案例(数据获取与处理)

文章目录 1. 代码解读1.1 代码展示1.2 流程介绍1.3 debug的方式逐行介绍 3. 知识点 1. 代码解读 1.1 代码展示 import json import numpy as np from tqdm import tqdmbert_model "bert-base-chinese"from transformers import AutoTokenizertokenizer AutoToken…

深入解析Spring Boot自动配置原理:让你的应用无痛集成

1.前言 1.1springboot的优势 Spring Boot是一个用于构建独立、生产级的Spring应用程序的开发框架&#xff0c;它在简化配置、提高开发效率、增强功能丰富性等方面具有以下优势&#xff1a; 简化配置&#xff1a;Spring Boot采用了约定优于配置的原则&#xff0c;通过自动配置和…

Java基于springboot开发的景点旅游项目

演示视频 https://www.bilibili.com/video/BV1cj411Y7UK/?share_sourcecopy_web&vd_source11344bb73ef9b33550b8202d07ae139b 主要功能&#xff1a;用户可浏览搜索旅游景点&#xff08;分为收费和免费景点&#xff09;&#xff0c;购票&#xff08;支持多规格套餐购票&am…

Unity3D实现页面的滑动切换功能

效果展示 Unity3D实现页面的滑动切换 效果 文章目录 前言一、先上代码二、创建UI1.创建Scroll View如下图&#xff0c;并挂载该脚本&#xff1a;2.Content下创建几个Itme 总结 前言 好记性不如烂笔头&#xff01; 一、先上代码 /*******************************************…

堆排序--C++实现

1. 简介 堆排序利用的是堆序性&#xff0c;最小堆进行从大到小的排序。 先建初堆&#xff0c;保证堆序性。将堆顶元素与最后一个元素交换&#xff0c; 就将当前堆中的最大(小)的元素放到了最后后。堆大小递减&#xff0c;再重新调整堆选出第二大&#xff0c;重复上述过程。 2…

python推导式特殊用法

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 字典推导式 >>> dic {x: x**2 for x in (2, 4, 6)} >>> dic {2: 4, 4: 16, 6: 36} >>> type(dic) <class dict>集合推导式 …

VSCode 的 C/C++ 开发环境的傻瓜级自动部署程序

软件介绍 VSCode 是一款优秀的编辑器&#xff0c;可以通过各种插件&#xff0c;将其配置成 C/C 开发环境。只是对于初学者而言&#xff0c;配置步骤有点繁琐。 软件 VSCode-Setup(MinGW) 提供了自动下载安装 VSCode 并配置成 C/C 开发环境的功能。无需担心该软件会对系统有额…

JavaWeb | JavaWeb开发环境相关知识点

JavaWeb开发环境相关知识点: 1.C/S结构、B/S结构2.浏览器与服务器的交互模式3.Tomcat安装目录中&#xff0c;比较重要的文件夹/文件4.怎么修改Tomcat端口&#xff1f;5.URL /url / 统一资源定位符 1.C/S结构、B/S结构 网络应用程序中&#xff0c;有 两种基本结构&#xff1a; C…

java.io.FileNotFoundException: D:\桌面\file3 (拒绝访问。)

java.io.FileNotFoundException: D:\桌面\file3 拒绝访问。 问题描述一、问题原因及其解决办法 问题描述 今天笔者使用FileInputStream输入流的时候&#xff0c;向里面添加了&#xff08;new File(“D://桌面//file3”)的File文件参数&#xff09;&#xff0c;最后不管怎样运行…

广州华锐互动:数字孪生可视化制作软件有哪些亮点?

由广州华锐互动开发的数字孪生可视化制作软件在当今的数字孪生领域中扮演着重要角色&#xff0c;它突破了许多传统数字孪生可视化制作软件的限制。以下是几个方面的突破&#xff1a; 无限自由度&#xff1a;传统的3D建模工具通常有限制编辑器的自由度&#xff0c;使用户难以进行…

KEDA:基于事件驱动扩展K8S应用的深度实践

新钛云服已累计为您分享773篇技术干货 为什么我们要自动扩展应用程序&#xff1f; 作为 SRE&#xff0c;需要保证应用弹性和高可用性。因此&#xff0c;自动缩放是我们需要的必须功能。通过自动缩放&#xff0c;我们能确保工作负载能够高效的地处理业务流量。 在本文中&#xf…

[vmware]vmware虚拟机压缩空间清理空间

vmware中的ubuntu使用如果拷贝文件进去在删除&#xff0c;vmare镜像文件并不会减少日积月累会不断是的真实物理磁盘空间大幅度减少&#xff0c;比如我以前windows操作系统本来只有30GB最后居然占道硬盘200GB&#xff0c;清理方法有2种。 第一种&#xff1a;vmware界面操作 第二…