CSP20230917-3 梯度求解 题解

发布时间 2023-10-24 10:08:57作者: cyx001

〇、题目

太长了懒得写。

简单来说就是求对于一个后缀表达式,每个询问给出一个下标和一些值,求以该下标变量为自变量其它变量为常数时的偏导数。

一、思路

考虑直接对于表达式建出表达式树。

建树的过程比较直接:每次栈里面放节点编号,遇到符号就取出当前栈顶两个节点作为子节点。

每次查询直接对整棵树爆搜,因为叶子节点一定是一个变量或一个常数,所以可以直接计算导数和原答案。

之后按照题目给出的公式直接代入即可。

二、代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
#define fi first
#define se second
#define endl '\n'
#define mp make_pair
#define pb push_back
#define all(x) x.begin(),x.end()
#define Cl(x) memset(x,0,sizeof(x))
const bool DC=0;
const ll mod=1e9+7;
const int N=0;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll qpow(ll a,ll b,ll p=mod){ll ans=1;for(;b;b>>=1,a=a*a%p)if(b&1)ans=ans*a%p;return ans;}
void NO(){cout<<"NO\n";}
void YES(){cout<<"YES\n";}
mt19937 rnd((unsigned long long)new char);

int n,m;
string s;int l;
string gt(){// 获取当前第一个单位字符串
	string ans;
	while(l<s.size()&&s[l]!=' ')ans+=s[l],l++;
	l++;
	return ans;
}
string ths[135];
stack<int>st;
int ls[135],rs[135],cnt;
int val[135],cur;
pii calc(int now){// 计算 now 的子树
	string s=ths[now];
	if(s[0]=='x'){// 变量
		int v=0;
		for(int i=1;i<s.size();i++)v=v*10+s[i]-48;
		return{(val[v]%mod+mod)%mod,v==cur};
	}
	if(s=="+"){// 符号
		pii l=calc(ls[now]),r=calc(rs[now]);
		return {(l.fi+r.fi)%mod,(l.se+r.se)%mod};
	}
	if(s=="-"){
		pii l=calc(ls[now]),r=calc(rs[now]);
		return {(l.fi+mod-r.fi)%mod,(l.se+mod-r.se)%mod};
	}
	if(s=="*"){
		pii l=calc(ls[now]),r=calc(rs[now]);
		return {1ll*l.fi*r.fi%mod,(1ll*l.se*r.fi%mod+1ll*r.se*l.fi%mod)%mod};
	}
	ll v=0;// 数
	int stt=(s[0]=='+'||s[0]=='-');
	bool f=(s[0]=='-');
	for(int i=stt;i<s.size();i++)v=v*10+s[i]-48;
	v%=mod;
	if(f)v=mod-v;
	return{v,0};
}
void __INIT__(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);}
void __SOLVE__(int _case){
	cin>>n>>m;getchar();
	getline(cin,s);
	string tmp;while((tmp=gt())!=""){
		++cnt;
		if(tmp=="+"||tmp=="-"||tmp=="*"){
			int a,b;
			b=st.top();
			st.pop();
			a=st.top();
			st.pop();
			ls[cnt]=a,rs[cnt]=b;// 拿出左右儿子
		}
		ths[cnt]=tmp;
		st.push(cnt);
	}
	while(m--){
		cin>>cur;
		for(int i=1;i<=n;i++)cin>>val[i];
		cout<<calc(cnt).se<<endl;
	}
}
int main(){/*freopen(".in","r",stdin);freopen(".out","w",stdout);__INIT__();*/int T;DC?cin>>T,1:T=1;for(int _CASE=1;_CASE<=T;_CASE++)__SOLVE__(_CASE);return 0;}

三、总结

正解不够恶心人。