题目回顾
梯度求解题目https://sim.csp.thusaac.com/contest/31/problem/2
c++满分题解
思路概述
从输入到输出,整理逻辑为:
接下来设计数据结构:
解析后最终用于求各测试点导数值的式子如果长成这样:(各个乘积项相加的多项式)
对求导的时候只需要进行如下操作:
#伪代码 |
1. 遍历多项式中的每个乘积项 |
2. 判断乘积项中不含有 |
3. 该项求导后值为0 |
4. 判断乘积项中含有 |
5. 该项求导后的值为 |
6. 累加各个乘积项的导数值 |
end |
于是我们定义乘积项数据结构:
struct chengjixiang {
map<int, int> dishu_cifang; //map中:key为底数,value为幂指数
long long changshu; //常数项
chengjixiang(map<int, int> d_c, long long cs) {
this->changshu = cs;
this->dishu_cifang = d_c;
}
};
多项式即为装有多个乘积项的数组:
struct duoxiangshi {
vector<chengjixiang> dxs;
duoxiangshi(vector<chengjixiang> d) {
this->dxs = d;
}
};
解析逆波兰式的过程其实就是进行多项式的 +、-、* 运算:
定义一个vector<duoxiangshi> stack 作为栈,存放解析过程中的多项式。
#伪代码 |
1. 遍历输入的逆波兰式 |
2. 如果是元素( 或 常数) |
3. stack.push_back(元素) |
4. 如果是运算符(+,-,*) |
5. stack.pop_back(),取出两个元素 |
6. 两个元素做相应运算,stack.pushback(结果) P.S stack中元素-1 |
end P.S 对于正确的逆波兰式输入,此时stack中应该只有一个元素 |
小贴士:
这里需要注意 ‘-’ 符号可能扮演两种角色:- 操作符号 and 负号,需要分类讨论。
分析到这基本上已经清晰了,只需要定义出三种操作便大功告成(bushi)
代码1.0(20分)
#include <iostream>
#include <math.h>
#include <iomanip>
#include <map>
#include <vector>
#include <string>
using namespace std;
struct chengjixiang {
map<int, int> dishu_cifang;
long long changshu;
chengjixiang(map<int, int> d_c, long long cs) {
this->changshu = cs;
this->dishu_cifang = d_c;
}
};
struct duoxiangshi {
vector<chengjixiang> dxs;
duoxiangshi(vector<chengjixiang> d) {
this->dxs = d;
}
};
bool isDigital(char c) {
return(c >= '0' && c <= '9');
}
void print_duoxiangshi(duoxiangshi d) {
vector<chengjixiang> c = d.dxs;
vector<chengjixiang>::iterator it;
map<int, int>::iterator mit;
for (it = c.begin(); it != c.end(); it++) {
cout << it->changshu << "*" << " ";
for (mit = it->dishu_cifang.begin(); mit != it->dishu_cifang.end(); mit++) {
cout << "x" << mit->first << "^" << mit->second << " ";
}
cout << " + ";
}
}
chengjixiang cjx_Multip(chengjixiang c1, chengjixiang c2) {
map<int, int> d_c;
long long cs;
int op;
cs = c1.changshu * c2.changshu;
for (map<int, int>::iterator pos = c1.dishu_cifang.begin(); pos != c1.dishu_cifang.end(); pos++) {
d_c[pos->first] = c1.dishu_cifang[pos->first] + c2.dishu_cifang[pos->first];
c2.dishu_cifang.erase(pos->first);
}
for (map<int, int>::iterator pos = c2.dishu_cifang.begin(); pos != c2.dishu_cifang.end(); pos++) {
d_c[pos->first] = c2.dishu_cifang[pos->first];
}
return chengjixiang(d_c, cs);
}
duoxiangshi dxs_Multip(duoxiangshi d1, duoxiangshi d2) {
vector<chengjixiang> result;
for (vector<chengjixiang>::iterator pos1 = d1.dxs.begin(); pos1 != d1.dxs.end(); pos1++) {
for (vector<chengjixiang>::iterator pos2 = d2.dxs.begin(); pos2 != d2.dxs.end(); pos2++)
result.push_back(cjx_Multip(*pos1, *pos2));
}
return duoxiangshi(result);
}
duoxiangshi dxs_add(duoxiangshi d1, duoxiangshi d2) {
vector<chengjixiang> result;
for (vector<chengjixiang>::iterator pos1 = d1.dxs.begin(); pos1 != d1.dxs.end(); pos1++)
result.push_back(*pos1);
for (vector<chengjixiang>::iterator pos2 = d2.dxs.begin(); pos2 != d2.dxs.end(); pos2++)
result.push_back(*pos2);
return result;
}
duoxiangshi dxs_sub(duoxiangshi d1, duoxiangshi d2) {
vector<chengjixiang> result;
for (vector<chengjixiang>::iterator pos1 = d1.dxs.begin(); pos1 != d1.dxs.end(); pos1++)
result.push_back(*pos1);
for (vector<chengjixiang>::iterator pos2 = d2.dxs.begin(); pos2 != d2.dxs.end(); pos2++) {
pos2->changshu *= -1;
result.push_back(*pos2);
}
return result;
}
duoxiangshi format(string str) {
vector<duoxiangshi> dxs;
vector<chengjixiang> cjx;
map<int, int> dishu_cifang;
map<int, int>::iterator t;
long long changshu = 1;
for (string::iterator pos = str.begin(); pos != str.end(); pos++) {
if (*pos == 'x') {
pos++;
int index = *pos - '0';
while (isDigital(*(++pos))) {
index = index * 10 + *pos - '0';
}
dishu_cifang[index] = 1;
cjx.push_back(chengjixiang(dishu_cifang, changshu));
dxs.push_back(duoxiangshi(cjx));
cjx.clear();
dishu_cifang.clear();
}
else if (*pos == '*') {
duoxiangshi d1 = dxs[dxs.size() - 1];
dxs.pop_back();
duoxiangshi d2 = dxs[dxs.size() - 1];
dxs.pop_back();
dxs.push_back(dxs_Multip(d1, d2));
}
else if (*pos == '+') {
duoxiangshi d1 = dxs[dxs.size() - 1];
dxs.pop_back();
duoxiangshi d2 = dxs[dxs.size() - 1];
dxs.pop_back();
dxs.push_back(dxs_add(d1, d2));
}
else if (*pos == '-') {
if(pos+1==str.end()){
duoxiangshi d1 = dxs[dxs.size() - 1];
dxs.pop_back();
duoxiangshi d2 = dxs[dxs.size() - 1];
dxs.pop_back();
dxs.push_back(dxs_sub(d2, d1));
}
else {
if (!isDigital(*(pos + 1))) {
duoxiangshi d1 = dxs[dxs.size() - 1];
dxs.pop_back();
duoxiangshi d2 = dxs[dxs.size() - 1];
dxs.pop_back();
dxs.push_back(dxs_sub(d1, d2));
}
else {
pos++;
changshu = *pos - '0';
while (isDigital(*(++pos))) {
changshu = changshu * 10 + *pos - '0';
}
changshu *= -1;
cjx.push_back(chengjixiang(dishu_cifang, changshu));
dxs.push_back(duoxiangshi(cjx));
changshu = 1;
cjx.clear();
}
}
}
else if(isDigital(*pos))
{
changshu = *pos - '0';
while (isDigital(*(++pos))) {
changshu = changshu * 10 + *pos - '0';
}
cjx.push_back(chengjixiang(dishu_cifang, changshu));
dxs.push_back(duoxiangshi(cjx));
changshu = 1;
cjx.clear();
}
}
if (dxs.size() == 1)
return dxs[0];
else {
cout << "error!!";
exit(0);
}
}
long long qiudao(duoxiangshi shizi, int testID, vector<long long> values){
long long mol = 1e9+7;
long long result = 0;
long long temp = 1;
vector<chengjixiang> dxs = shizi.dxs;
vector<chengjixiang>::iterator it;
map<int, int>::iterator mit;
map<int, int>::iterator t;
for(it = dxs.begin(); it != dxs.end(); it++){
// 计算单个乘积项的导数值
temp *= it->changshu;
for(mit = it->dishu_cifang.begin(); mit != it->dishu_cifang.end(); mit++){
t = it->dishu_cifang.find(testID);
if(t!=it->dishu_cifang.end()){
// 如果这一项中存在xi
if(mit->first == testID){
temp *= mit->second;
for(int s=0; s<mit->second-1; s++)
temp *= values[testID];
}
else{
for(int s=0; s<mit->second; s++)
temp *= values[mit->first];
}
}
else{
temp = 0;
}
}
result += temp;
//cout << temp << " ";
temp = 1;
}
result = result % mol;
result = result>=0 ? result : result+mol;
return result;
}
int main() {
int n, m;
long long result;
string str;
vector<long long> values(110);
int testID;
cin >> n >> m;
char c = getchar();
getline(cin, str);
duoxiangshi zuizhongshizi = format(str);
//print_duoxiangshi(zuizhongshizi);
for(int mm=0; mm<m; mm++){
cin >> testID;
for(int nn=1; nn<=n; nn++){
cin >> values[nn];
}
result = qiudao(zuizhongshizi, testID, values);
cout << result << endl;
}
}
居然只有20分,离谱。前两个用例居然也没有对。于是看来子任务描述,前两个用例只有一个元素!!!我恍然大悟,可能是str越界了。
代码1.0中,我假设了一个正确的逆波兰式输入的最后一个字符,只能是运算符,所以没有必要对其他情况做越界保护。这个结论乍一看是正确的,但是如果只输入一个元素呢。。。。。。。于是我对元素读取部分添加了越界保护(不要偷懒,不要偷懒,不要偷懒)
代码2.0修改部分(40分)
if (*pos == 'x') {
pos++;
int index = *pos - '0';
//****************越界保护*****************
if(pos+1 != str.end()){
while (isDigital(*(++pos))) {
index = index * 10 + *pos - '0';
}
}
dishu_cifang[index] = 1;
cjx.push_back(chengjixiang(dishu_cifang, changshu));
dxs.push_back(duoxiangshi(cjx));
cjx.clear();
dishu_cifang.clear();
}
else if(isDigital(*pos))
{
changshu = *pos - '0';
//****************越界保护*****************
if(++pos != str.end()){
while (isDigital(*pos)) {
changshu = changshu * 10 + *pos - '0';
pos++;
//****************越界保护*****************
if(pos == str.end()){
pos--; //回退到最后一个元素指针
break;
}
}
}
cjx.push_back(chengjixiang(dishu_cifang, changshu));
dxs.push_back(duoxiangshi(cjx));
changshu = 1;
cjx.clear();
}
然后检查发现,自己粗心把减运算的被减数减数搞反了,于是有了代码3.0.
代码3.0(80分)
else if (*pos == '-') {
if(pos+1==str.end()){
duoxiangshi d1 = dxs[dxs.size() - 1];
dxs.pop_back();
duoxiangshi d2 = dxs[dxs.size() - 1];
dxs.pop_back();
dxs.push_back(dxs_sub(d2, d1));
}
else {
if (!isDigital(*(pos + 1))) {
duoxiangshi d1 = dxs[dxs.size() - 1];
dxs.pop_back();
duoxiangshi d2 = dxs[dxs.size() - 1];
dxs.pop_back();
//***************先d2,再d1********************
dxs.push_back(dxs_sub(d2, d1));
}
最后两个用例没通过,一般应该不是代码的问题了(因为7、8和9、10测试用例的表达式性质是一样的,不一样的只是自变量的个数)。于是我想到,可能是乘积项计算出来的值太大了,导致溢出截断,怎么办呢?在每次乘法运算后加上取模操作就能完美解决!
最终代码(100分)
#include <iostream>
#include <math.h>
#include <iomanip>
#include <map>
#include <vector>
#include <string>
using namespace std;
long long mol = 1e9+7;
struct chengjixiang {
map<int, int> dishu_cifang;
long long changshu;
chengjixiang(map<int, int> d_c, long long cs) {
this->changshu = cs;
this->dishu_cifang = d_c;
}
};
struct duoxiangshi {
vector<chengjixiang> dxs;
duoxiangshi(vector<chengjixiang> d) {
this->dxs = d;
}
};
bool isDigital(char c) {
return(c >= '0' && c <= '9');
}
void print_duoxiangshi(duoxiangshi d) {
vector<chengjixiang> c = d.dxs;
vector<chengjixiang>::iterator it;
map<int, int>::iterator mit;
for (it = c.begin(); it != c.end(); it++) {
cout << it->changshu << "*" << " ";
for (mit = it->dishu_cifang.begin(); mit != it->dishu_cifang.end(); mit++) {
cout << "x" << mit->first << "^" << mit->second << " ";
}
cout << " + ";
}
}
chengjixiang cjx_Multip(chengjixiang c1, chengjixiang c2) {
map<int, int> d_c;
long long cs;
int op;
cs = c1.changshu * c2.changshu;
cs = cs>mol ? cs-mol : cs;
for (map<int, int>::iterator pos = c1.dishu_cifang.begin(); pos != c1.dishu_cifang.end(); pos++) {
d_c[pos->first] = c1.dishu_cifang[pos->first] + c2.dishu_cifang[pos->first];
c2.dishu_cifang.erase(pos->first);
}
for (map<int, int>::iterator pos = c2.dishu_cifang.begin(); pos != c2.dishu_cifang.end(); pos++) {
d_c[pos->first] = c2.dishu_cifang[pos->first];
}
return chengjixiang(d_c, cs);
}
duoxiangshi dxs_Multip(duoxiangshi d1, duoxiangshi d2) {
vector<chengjixiang> result;
for (vector<chengjixiang>::iterator pos1 = d1.dxs.begin(); pos1 != d1.dxs.end(); pos1++) {
for (vector<chengjixiang>::iterator pos2 = d2.dxs.begin(); pos2 != d2.dxs.end(); pos2++)
result.push_back(cjx_Multip(*pos1, *pos2));
}
return duoxiangshi(result);
}
duoxiangshi dxs_add(duoxiangshi d1, duoxiangshi d2) {
vector<chengjixiang> result;
for (vector<chengjixiang>::iterator pos1 = d1.dxs.begin(); pos1 != d1.dxs.end(); pos1++)
result.push_back(*pos1);
for (vector<chengjixiang>::iterator pos2 = d2.dxs.begin(); pos2 != d2.dxs.end(); pos2++)
result.push_back(*pos2);
return result;
}
duoxiangshi dxs_sub(duoxiangshi d1, duoxiangshi d2) {
vector<chengjixiang> result;
for (vector<chengjixiang>::iterator pos1 = d1.dxs.begin(); pos1 != d1.dxs.end(); pos1++)
result.push_back(*pos1);
for (vector<chengjixiang>::iterator pos2 = d2.dxs.begin(); pos2 != d2.dxs.end(); pos2++) {
pos2->changshu *= -1;
result.push_back(*pos2);
}
return result;
}
duoxiangshi format(string str) {
vector<duoxiangshi> dxs;
vector<chengjixiang> cjx;
map<int, int> dishu_cifang;
map<int, int>::iterator t;
long long changshu = 1;
for (string::iterator pos = str.begin(); pos != str.end(); pos++) {
if (*pos == 'x') {
pos++;
int index = *pos - '0';
if(pos+1 != str.end()){
while (isDigital(*(++pos))) {
index = index * 10 + *pos - '0';
}
}
dishu_cifang[index] = 1;
cjx.push_back(chengjixiang(dishu_cifang, changshu));
dxs.push_back(duoxiangshi(cjx));
cjx.clear();
dishu_cifang.clear();
}
else if (*pos == '*') {
duoxiangshi d1 = dxs[dxs.size() - 1];
dxs.pop_back();
duoxiangshi d2 = dxs[dxs.size() - 1];
dxs.pop_back();
dxs.push_back(dxs_Multip(d1, d2));
}
else if (*pos == '+') {
duoxiangshi d1 = dxs[dxs.size() - 1];
dxs.pop_back();
duoxiangshi d2 = dxs[dxs.size() - 1];
dxs.pop_back();
dxs.push_back(dxs_add(d1, d2));
}
else if (*pos == '-') {
if(pos+1==str.end()){
duoxiangshi d1 = dxs[dxs.size() - 1];
dxs.pop_back();
duoxiangshi d2 = dxs[dxs.size() - 1];
dxs.pop_back();
dxs.push_back(dxs_sub(d2, d1));
}
else {
if (!isDigital(*(pos + 1))) {
duoxiangshi d1 = dxs[dxs.size() - 1];
dxs.pop_back();
duoxiangshi d2 = dxs[dxs.size() - 1];
dxs.pop_back();
dxs.push_back(dxs_sub(d2, d1));
}
else {
pos++;
changshu = *pos - '0';
if(pos+1 != str.end()){
while (isDigital(*(++pos))) {
changshu = changshu * 10 + *pos - '0';
}
}
changshu *= -1;
cjx.push_back(chengjixiang(dishu_cifang, changshu));
dxs.push_back(duoxiangshi(cjx));
changshu = 1;
cjx.clear();
}
}
}
else if(isDigital(*pos))
{
changshu = *pos - '0';
if(++pos != str.end()){
while (isDigital(*pos)) {
changshu = changshu * 10 + *pos - '0';
pos++;
if(pos == str.end()){
pos--;
break;
}
}
}
cjx.push_back(chengjixiang(dishu_cifang, changshu));
dxs.push_back(duoxiangshi(cjx));
changshu = 1;
cjx.clear();
}
}
if (dxs.size() == 1)
return dxs[0];
else {
cout << "error!!";
exit(0);
}
}
long long qiudao(duoxiangshi shizi, int testID, vector<long long> values){
long long result = 0;
long long temp = 1;
vector<chengjixiang> dxs = shizi.dxs;
vector<chengjixiang>::iterator it;
map<int, int>::iterator mit;
map<int, int>::iterator t;
for(it = dxs.begin(); it != dxs.end(); it++){
// 计算单个乘积项的导数值
temp *= it->changshu;
temp = temp%mol;
t = it->dishu_cifang.find(testID);
if(t==it->dishu_cifang.end()){
// 如果这一项中不存在xi
temp = 0;
}
else{
for(mit = it->dishu_cifang.begin(); mit != it->dishu_cifang.end(); mit++){
if(mit->first == testID){
temp *= mit->second;
temp = temp%mol;
for(int s=0; s<mit->second-1; s++){
temp *= values[testID];
temp = temp%mol;
}
}
else{
for(int s=0; s<mit->second; s++){
temp *= values[mit->first];
temp = temp%mol;
}
}
}
}
result += temp;
result = result%mol;
//cout << temp << " ";
temp = 1;
}
result = result%mol;
result = result>=0 ? result : result+mol;
return result;
}
int main() {
int n, m;
long long result;
string str;
vector<long long> values(110);
int testID;
cin >> n >> m;
char c = getchar();
getline(cin, str);
duoxiangshi zuizhongshizi = format(str);
//print_duoxiangshi(zuizhongshizi);
for(int mm=0; mm<m; mm++){
cin >> testID;
for(int nn=1; nn<=n; nn++){
cin >> values[nn];
}
result = qiudao(zuizhongshizi, testID, values);
cout << result << endl;
}
}