一道神奇的求多项式题-多项式还原

题目:多项式还原

内存限制:128Mb

时间限制:1s

题目描述

最近学校的数学课上老师在讲解有关多项式的知识,所谓多项式是指形如f(x)=a_{0}{x}^{0}+a_{1}{x}^{1}+a_{2}{x}^{2}+...+a_{k}{x}^{k}的式子,其中a_{i}为已知数,称为系数;x为未知数;f(x)为运算结果;a_{i}x^{i}为其中的一项,i为幂次。

在课外班学习编程的小明发现了多项式的一项奥秘,经过一周的查证和练习后,他找到小刚说自己可以由运算结果猜出运算的多项式,前提条件是多项式各系数都是非负整数,小刚觉得很有意思,便随手写下了一个多项式后让小明去猜:

  • 小明询问x=1时多项式的运算结果,小刚回答说n
  • 小明紧跟着询问x=n+1时的运算结果,小刚回答说m

然后小明居然真的还原出了小刚写下的式子,小刚觉得可能是自己的式子太简单了被轻易猜出,便写了一个更为复杂的多项式让小明猜,结果小明因为运算量太大和粗心算错了,他想如果这个功能能编成程序交给电脑去运算的话就绝不会出错了,但他自己不会,便找来会编程的你来帮忙。

现在给定n、m,试着还原并输出该多项式,格式要求如下:

  • 从系数非零的最高幂次项开始倒序输出
  • 输出时用符号'^'表示幂运算,比如"x^3"
  • 对于一项a_{i}x^{i},若a_{i}=0,则不输出该项
  • 对于一项a_{i}x^{i},若a_{i}=1,则只输出x^{i}
  • 对于一项a_{i}x^{i},若i=1,只输出a_{i}x
  • 对于一项a_{i}x^{i},若i=0,只输出a_{i}

输入

输入格式:

  • 输入一行两个数n、m。

输出

输出格式:

  • 按要求格式输出还原出的多项式,数据保证有唯一解。

样例输入1

10 484540

样例输出1

3x^5+x^3+5x+1

提示

数据范围:1\leq n\leq 1001\leq m\leq 10^{9}

思路

这道题只给了两个数,但是要还原出整个多项式,猜想给出的两个条件之间有联系,先把式子列出来:

f(1)=a_{0}+a_{1}+a_{2}+...+a_{k}=n

f(n+1)=a_{0}(n+1)^{0}+a_{1}(n+1)^{1}+a_{2}(n+1)^2+...+a_{k}(n+1)^{k}=m

发现多项式系数之和是n,然后带了一个数算出的结果是m

因为多项式各系数都是非负整数,所以算出来的nm也是非负整数。

又因为n\geq 1,那么n+1\geq 2,所以对于f(n+1)这个多项式,其忽略系数的x^{i}项是单调递增的。

有什么用呢?也就是说(n+1)^{0}<(n+1)^{1}<...<(n+1)^{i}<...<(n+1)^{k},它又是非负整数,所以可以利用向下取整,把商小于1的直接变成0,那么最后剩下的只有当前最高次项的系数了!

解释一下:

一开始让m也就是f(n+1)除以(n+1)^{k},由于除了\frac{(n+1)^{k}}{(n+1)^{k}}=1之外,其余项都小于1,由于向下取整,全部变为0,所以得到的商就是本次最高次数k次项的系数a_{k}

m中减去a_{k}(n+1)^{k}项,此时再重复上面一步,求k-1次项的系数,直到系数和减至0或多项式和减至0。

分析

结构体记录多项式系数(x)和次数(c),用队列记录多项式每一项。

多项式和还没减到0,不停除直到获得最高次数,从当前和中计算最高次项并减去,系数和次数入队,次数重置,程序继续。

    while (sum > 0)
    {
        while (tmp > 0)
        {
            tmp /= n + 1;
            cnt++;
        }
        ak = sum / pow(n + 1, cnt);
        sum -= ak * pow(n + 1, cnt);
        tmp = sum;
        q.push({ ak,cnt });
        cnt = -1;
    }

按照题目要求,格式化输出。

    while (!q.empty())
    {
        if (q.front().x != 1)
        {
            cout << q.front().x;
        }
        if (q.front().c == 1)
        {
            cout << "x";
        }
        else if (q.front().c != 0)
        {
            cout << "x^" << q.front().c;
        }
        else
        {
            if (q.front().x == 1)
            {
                cout << q.front().x;
            }
        }
        
        q.pop();
        
        if (!q.empty())
        {
            cout << "+";
        }
    }

复杂度和优化

时间:O(k^{2}),因为每一轮都要找到最高次项。

空间:O(k),分配了一个记录每一项的队列。

优化:单独维护一个变量,记录最高次项,下一轮减1,可以降低时间复杂度。(会吧会吧)

代码

以下是C++代码:

#include <iostream>
#include <unordered_map>
#include <string>
#include <queue>
#include <cmath>
using namespace std;

struct DXS
{
    int x;
    int c;
};

int main() 
{
    int n, m;
    cin >> n >> m;
    queue<DXS>q;
    int tmp = m;
    int cnt = -1;
    int ak = 0;
    int sum = m;
    while (sum > 0)
    {
        while (tmp > 0)
        {
            tmp /= n + 1;
            cnt++;
        }
        ak = sum / pow(n + 1, cnt);
        sum -= ak * pow(n + 1, cnt);
        tmp = sum;
        q.push({ ak,cnt });
        cnt = -1;
    }
    
    while (!q.empty())
    {
        if (q.front().x != 1)
        {
            cout << q.front().x;
        }
        if (q.front().c == 1)
        {
            cout << "x";
        }
        else if (q.front().c != 0)
        {
            cout << "x^" << q.front().c;
        }
        else
        {
            if (q.front().x == 1)
            {
                cout << q.front().x;
            }
        }
        
        q.pop();
        
        if (!q.empty())
        {
            cout << "+";
        }
    }

    return 0;
}

纯小白,代码写的vegetable,轻喷orz

  • 28
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值