CSP-202112-3-登机牌

1 篇文章 0 订阅

参考

参考题解1
上面那位博主其实说的很仔细,可能多项式有点晦涩,但理解之后发现博主确实说的挺详细的。

计算 g ( x ) g(x) g(x)

这道题多项式的第一个难点在于如何计算多项式 g ( x ) g(x) g(x)的各项系数。
根据题目描述,可以知道 g ( x ) = ( x − 3 ) ⋅ ( x − 3 2 ) ⋅ . . . ⋅ ( x − 3 k ) g(x)=(x-3)·(x-3^2)·...·(x-3^k) g(x)=(x3)(x32)...(x3k)
我记得老师教过一个方法,就是说如果要计算括号展开后, x j x^j xj的系数 a j a_j aj,那么 a j a_j aj一定是由形如 x m ⋅ x n , s . t . m + n = j x^m·x^n,s.t. m+n=j xmxn,s.t.m+n=j这些幂次构成的,所以某一项的系数其实由下面给出: a j = ∑ ∀ m , n , m + n = j a m ⋅ a n a_j=\sum_{{{\forall}}m,n, \\m+n=j}a_m·a_n aj=m,n,m+n=jaman

但一口气算完是不现实的,其实可以按照两个括号两个括号的逐次合并。一共有 k k k个括号,那么需要合并 k − 1 k-1 k1次。

比如我们先合并 q 2 ( x ) = ( x − 3 ) ⋅ ( x − 3 2 ) q_2(x)=(x-3)·(x-3^2) q2(x)=(x3)(x32),
再合并 q 3 ( x ) = q 2 ( x ) ⋅ ( x − 3 3 ) q_3(x)=q_2(x)·(x-3^3) q3(x)=q2(x)(x33)于是变成了一个动态规划。这道题可以看到,含有 x x x的每个括号其次数都为1,那么就可以先确定出初始状态 G [ k ] = − 3 , G [ k − 1 ] = 1 G[k]=-3,G[k-1]=1 G[k]=3,G[k1]=1

我们欲从低次 ( x − 3 ) (x-3) (x3)推的 x k x^k xk的系数 G [ 0 ] G[0] G[0],从而确定出每一次数的系数。

再以上面合并 q 2 ( x ) = ( x − 3 ) ( x − 3 2 ) q_2(x)=(x-3)(x-3^2) q2(x)=(x3)(x32)时为例,可以看到这两项合并最高次数为2,并且只能由 x ⋅ x x·x xx构成。所以可以填入 G [ k − 2 ] = 1 G[k-2]=1 G[k2]=1

由于当前合并的是第1个括号和第2个括号,那么此时还有i=0,所以准确来说是 G [ k − 2 − i ] = 1 G[k-2-i]=1 G[k2i]=1

对于 q 2 ( x ) q_2(x) q2(x)的其他幂次,比如 x = x 1 x=x^1 x=x1,那么 q 2 ( x ) q_2(x) q2(x)的一次项系数,它可以由第一个括号的x乘上第二个括号的系数( − 9 -9 9),和第二个括号的 x x x乘上第一个括号的系数 ( − 3 ) (-3) (3)相加得到。
按道理来说这里如果括号里也是个多项式,那就很麻烦了,好在他每个括号都是一次的。所以合并之后的 x j x_j xj一定来自于先前 x j x_j xj的系数乘上待合并括号的常数,再加上原来 x j − 1 x_{j-1} xj1的系数乘上新括号 x x x的系数(恒等于1)相加得到。

为了代码实现,所以在每次合并括号,都会先记录一下当前多项式,以免覆盖。

多项式相除

这便是第二个难点了。我比较笨,看着博主代码想了很久。事实上代码的多项式相除比手算简便,因为手算还需要确定该乘多少次才能对其。但事实上,代码实现时,只关心当前该乘多少系数,也就是当前被除数最高位的系数。

因为我们用数组来表示多项式了,乘 x x x的幂次的操作不过是数组的对其方式罢了。事实上用第0位表示当前多项式最高次,就隐含了对齐这个操作了。

存放checksum

按道理可以在 D ( x ) D(x) D(x)上原地更新存放校验码,但是直接将 D ( x ) D(x) D(x)多开几位( k − 1 k-1 k1次多项式便是长度为k的数组)使得k-1次多项式能够存下就好了,以免折腾。

到此这道题就完成的差不多了。

代码
#include <iostream>
#include <vector>
#include <valarray>

using namespace std;
int w, s;
int UPPER = 0;
int LOWER = 1;
int DIGIT = 2;

void
coding(string &input, vector<int> &vec) {
    int state = UPPER;
    for (int i = 0; i < input.length(); ++i) {
        if ('A' <= input[i] && input[i] <= 'Z') {
            // UPPER
            if (state == LOWER) {
                // LOWER -> DIGIT -> UPPER
                vec.push_back(28);
                vec.push_back(28);
            } else if (state == DIGIT) {
                vec.push_back(28);
            }
            vec.push_back(input[i] - 'A');
            state = UPPER;
        } else if ('a' <= input[i] && input[i] <= 'z') {
            if (state != LOWER) {
                vec.push_back(27);
            }
            vec.push_back(input[i] - 'a');
            state = LOWER;
        } else if ('0' <= input[i] && input[i] <= '9') {
            if (state != DIGIT) {
                vec.push_back(28);
            }
            vec.push_back(input[i] - '0');
            state = DIGIT;
        }
    }
}

int mazi(int a, int b) {
    return 30 * a + b;
}

void
mazi(vector<int> &code, vector<int> &ma) {
    for (int i = 0; i < code.size(); i += 2) {
        ma.push_back(mazi(code[i], code[i + 1]));
    }

}


ostream &operator<<(ostream &os, vector<int> &m) {
    for (auto &x: m) {
        cout << x << "\n";
    }
    return os;
}

int MOD = 929;


int main() {
    cin >> w >> s;
    string raw_str;
    cin >> raw_str;
    vector<int> coded;
    coding(raw_str, coded);

    if (coded.size() % 2 == 1) {
        coded.push_back(29);
    }
    vector<int> mazied;
    mazi(coded, mazied);

    int k = s != -1  ? pow(2, s + 1)  : 0;
    while ((mazied.size() + k + 1) % w != 0) {
        mazied.push_back(900);
    }
    cout << mazied.size() + 1 << "\n";

    if (s != -1) {

        // construct k polynomial, G[0] means the x^k, G[1] means x^{k-1}, ..., x^2, x ,C
        vector<int> G(k + 1, 0);
        G[k] = -3;
        G[k - 1] = 1;
        // (x^2 - 9)
        int tmp_C = -9;

        // calc our G(x), follow (x-3) * (x-3^2) ..
        for (int i = 0; i < k - 1; ++i) {
            vector<int> old_G(k + 1);
            for (int j = k - i - 1; j <= k; ++j) {
                old_G[j] = G[j];
            }

            /**
             * for example:
             * (x-3)(x-3^2)
             * we know G[k] = -3,G[k-1] = 1 ( as we see (x-3) here)
             * then going to multiply to (x^2 - 9) (why tmp_C = - 9 here)
             * update C(x^1) = G[k-1] = -9 + (-3) = G[k-1] * tmp_C + G[k-2] = G[k-1] * tmp_C + old_G[k]
             * */
            for (int j = k - i - 1; j <= k; ++j) {
                G[j] = (G[j] % MOD) * (tmp_C % MOD) % MOD;
            }
            for (int j = k - i - 1; j < k; ++j) {
                // consider lower index will also construct this
                G[j] += old_G[j + 1] % MOD;
            }
            // as we multiply each loop,
            // the current highest must construct by all x param, so must be 1
            G[k - i - 2] = 1;
            tmp_C *= 3;
            tmp_C %= MOD;
        }
        vector<int> D(mazied.size() + 1 + k,0);
        D[0] = mazied.size() + 1;
        for (int i = 0; i < mazied.size(); ++i) {
            D[i+1] = mazied[i];
            D[i+1] %= MOD;
        }
        auto polynomial_divide = [&k, &mazied](vector<int> &Dx, vector<int> &Gx) {
            /**
             * Dx/Gx
             * */
            // the divide means, we will align the low index to high poly index,
            // so for each param in Gx, we will multiply them as D(x) current high poly param
            // i=0 for the highest index
            for (int i = 0; i < Dx.size() - k; ++i) {
                int current_C = Dx[i];
                // multiply all poly in Gx by C
                // Gx[0] is x^k
                for (int j = 0; j < Gx.size(); ++j) {
                    Dx[i + j] = Dx[i + j] - ((Gx[j] * current_C) % MOD);
                    Dx[i + j] %= MOD;
                }
            }
            //update checksum
            for (long long i = Dx.size() - Gx.size() + 1; i < Dx.size(); ++i) {
                if (-Dx[i] < 0)
                    mazied.push_back(MOD+ (-Dx[i] % MOD));
                else
                    mazied.push_back(-Dx[i] % MOD);

            }
//            cout << Gx;
        };
//        cout << "D=" << D;
//        cout << "G=" << G;
        polynomial_divide(D, G);

    }
    cout << mazied;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值