2023.09 CCF-CSP 认证 第三题 《梯度求解》 80分

题目链接
刚开始完全没想法,索性用导数定义求解,将自变量和自变量减0.000001带入求函数值,用两个函数值之差除以0.000001,最后结果再四舍五入。只得了50分。
后来想到最适合求导的就是多项式形式,一个数组就是一个多项式,下标就是一项的指数,值就是一项的系数。后缀表达式求值的方法也可以用来算多项式。
不过还是没AC,只有80分,不知道问题在哪。
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

//从字符串得到逆波兰
vector<string> getfi(string s) {
	vector<string> fi;
	stringstream ss(s);
	string item;
	while (getline(ss, item, ' ')) {
		if (!item.empty()) {
			fi.emplace_back(item);
		}
	}
	return fi;
}

//把所有其他数字带入逆波兰,xi是X的序号
vector<string> getni(vector<string> fi, int xi, vector<ll> xs) {
	for (int i = 0; i < fi.size(); i++) {
		string fii = fi[i];
		if (fii[0] == 'x') {
			fii.erase(fii.begin());
			int fiii = stoi(fii);
			fiii--;
			//如果不是要求的未知数
			if (fiii != xi) {
				fi[i] = to_string(xs[fiii]);
			}else {
				fi[i] = "x";
			}

		}
	}
	return fi;
}


//两个多项式计算
//多项式以数组存储,数组下标即是指数,数据即是系数。
vector<ll> cal(vector<ll> v1, vector<ll> v2, string op) {
	int n1 = v1.size(), n2 = v2.size();
	vector<ll> re;
	if (op == "+") {
		re.resize(max(n1, n2));
		for (int i = 0; i < re.size(); i++) {
			ll v11 = 0, v22 = 0;
			if (i < v1.size())v11 = v1[i];
			if (i < v2.size())v22 = v2[i];
			re[i] = v11 + v22;
		}

	}
	if (op == "-") {
		re.resize(max(n1, n2));
		for (int i = 0; i < re.size(); i++) {
			ll v11 = 0, v22 = 0;
			if (i < v1.size())v11 = v1[i];
			if (i < v2.size())v22 = v2[i];
			re[i] = v11 - v22;
		}
	}
	if (op == "*") {
		re.resize(n1 + n2 - 1);
		for (int i = 0; i < n1; i++) {
			for (int j = 0; j < n2; j++) {
				re[i + j] = re[i + j] + v1[i] * v2[j];
			}
		}
	}
	return re;
}

//对整个多项式求导,系数乘以指数为新的系数,指数减一为新的指数
ll dao(vector<ll> y, ll x) {
	int n = y.size();
	ll re = 0;

	for (int i = 0; i < n - 1; i++) {
		re += (y[i + 1] * (i + 1)) * pow(x, i);
	}
	return re;
}

//把逆波兰表达式计算为一个多项式形式
vector<ll> count(vector<string> ni) {
	int n = ni.size();
	stack<vector<ll>> ns;
	for (int i = 0; i < n; i++) {
		string nx = ni[i];
		if (nx == "+") {
			vector<ll> v1 = ns.top();
			ns.pop();
			vector<ll> v2 = ns.top();
			ns.pop();
			ns.push(cal(v1, v2, "+"));
		}else if (nx == "-") {
			vector<ll> v2 = ns.top();
			ns.pop();
			vector<ll> v1 = ns.top();
			ns.pop();
			ns.push(cal(v1, v2, "-"));
		}else if (nx == "*") {
			vector<ll> v1 = ns.top();
			ns.pop();
			vector<ll> v2 = ns.top();
			ns.pop();
			ns.push(cal(v1, v2, "*"));
		}else {
			if (nx == "x") {
				vector<ll>t = { 0,1 };
				ns.push(t);
			}
			else {
				vector<ll>t = { stoll(nx) };
				ns.push(t);
			}
		}
	}

	return ns.top();

}

int main() {
	int n, m;
	cin >> n >> m;
	string s;
	cin.get();
	getline(cin, s);
	long long po = pow(10, 9) + 7;
	vector<string> fi = getfi(s);
	for (int i = 0; i < m; i++) {
		ll xi;
		cin >> xi;
		xi--;
		vector<ll> xs;
		for (int j = 0; j < n; j++) {
			ll xj;
			cin >> xj;
			xs.emplace_back(xj);
		}
		vector<string> ni = getni(fi, xi, xs);
		vector<ll> y = count(ni);
		ll re = dao(y, xs[xi]);

		re = re % po;
		if (re < 0)re += po;
		cout << re << endl;
	}
	return 0;
}


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值