小朋友学Codeforces(5):Round 453 DIV 2, 902D

一、题目

http://codeforces.com/contest/902/problem/D

二、思路

(一)最大公约数的辗转相除法

对于两个整数a、b,求最大公约数gcd(a,b)的辗转相除法的算法如下

// 辗转相除法 + 递归 
int gcd(int num1, int num2) 
{
    if(0 == num2) 
    {
        return num1;
    }

    return gcd(num2, num1 % num2);
}

(二)题意分析

对于多项式A(x),定义deg A(x)为多项式的次数。对于多项式A、B,定义多项式mod运算:若A(x)=B(x)·D(x)+R(x),deg R(x)

(三)本题的思路

辗转相除将多项式对(A,B)转化成(B,A mod B),最终A mod B为0时,B即为所求。

考虑整数Fibonacci数列:F(0)=1,F(1)=1,F(n+1)=F(n)+F(n-1)。

于是,一次辗转相除法将(F(n+1),F(n))转化成(F(n),F(n-1))。于是,(F(n),F(n-1))在n次辗转相除后结束操作。

类似地,构造多项式的情形:
P(0) = 1
P(1) = x
P(n + 1) = x·P(n) ± P(n-1)

递推时,维护P(n+1)的系数在{-1,0,1}中取值,这可以通过符号选择(+/-)实现。

若只取“+”号,还可以进一步构造多项式:
P(0) = 1
P(1) = x
P(n + 1) ≡ [x·P(n) + P(n-1)] mod 2 ①
这里mod 2是为了保证,系数不要超过1。

(四)例子

例1:根据式子①,求P(0)~p(5)
P(0) = 1
P(1) = x
P(2) = x ^ 2 + 1
P(3) = [x ^ 3 + x + x] mod 2 = x ^ 3
P(4) = x ^ 4 + x ^ 2 + 1
P(5) = [x ^ 5 + x ^ 3 + x + x ^ 3] mod 2 = x ^ 5 + x

例2:根据P(n + 1) = x·P(n) + P(n-1),求P(2) / P(1)
P(2) / P(1)
= (x ^ 2 + 1) / x
= x …… 1
这里的余数1 等于 P(0)

例3:P(n + 1) = x·P(n) + P(n-1),求P(3) / P(2)
P(3) / P(2)
= x ^ 3 / (x ^ 2 + 1)
= x …… -x
这里余数-x不完全等于P(1),差了一个正负号。
这是因为,用P(2)和P(1)计算P(3)的时候,用了mod 2运算,使得x的系数变为0。
否则用没取模之前的P(3) = x ^ 3 + 2x去除P(2),余数正好等于P(1)

三、代码

#include <iostream>
using namespace std;

#define MAX_N 200
int p[MAX_N][MAX_N];

int main()
{
    // 被除数多项式的次数 
    int deg;
    cin >> deg;

    // P(0) = 1, P(x) = x
    p[0][0] = 1;
    p[1][1] = 1;

    // p[i + 1] = {x * p[i] + p[i - 1]} % 2;
    // 从第2行一直计算到第n行 
    for (int i = 1; i < deg; i++) 
    {
        // x * p[i] 
        for (int j = 0; j <= i; j++)
        {
            p[i + 1][j + 1] += p[i][j];
        }

        // + p[i - 1]    
        for (int j = 0; j <= i - 1; j++)
        {
            p[i + 1][j] += p[i - 1][j];
        }

        // % 2 
        for (int j = 0; j <= i + 1; j++)
        {
            p[i + 1][j] %= 2;
        }

    }

    // 打印被除数多项式的次数 
    cout << deg << "\n";
    // 打印被除数多项式的系数,最常数项系数到最高次系数的顺序 
    for (int i = 0; i <= deg; i++)
    {
        cout << p[deg][i] << " ";
    }
    cout << "\n";

    // 打印除数多项式的次数,比被除数多项式的次数少1 
    cout << deg - 1 << "\n";

    // 打印除数多项式的系数,按最常数项系数到最高次系数的顺序
    for (int i = 0; i <= deg - 1; i++)
    {
        cout << p[deg - 1][i] << " ";
    }
    cout << "\n";

    return 0;
}



更多内容请关注微信公众号
wechat.jpg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值