CSP-梯度求解 满分题解(从20分debug到100的心路历程)

题目回顾

梯度求解题目icon-default.png?t=N7T8https://sim.csp.thusaac.com/contest/31/problem/2

c++满分题解

思路概述

从输入到输出,整理逻辑为:

接下来设计数据结构:

解析后最终用于求各测试点导数值的式子如果长成这样:(各个乘积项相加的多项式)

                  f(x_{1}, x_{2}, ..., x_{n})) = c_{1}x_{i1}^{a1}...x_{j1}^{b1}+c_{2}x_{i2}^{a2}...x_{j2}^{b2}+...+c_{l}x_{il}^{al}...x_{jl}^{bl}

        对x_{i1}求导的时候只需要进行如下操作:

#伪代码
1. 遍历多项式中的每个乘积项
        2. 判断乘积项中不含有x_{i1}
                3. 该项求导后值为0
        4. 判断乘积项中含有x_{i1}
                5. 该项求导后的值为a_{1}c_{1}x_{i1}^{a1-1}...x_{j1}^{b1}
        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. 如果是元素(x_{i} 或 常数)
                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;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值