CSP202112——T3登机牌条码

其实题目已经给了模拟思路了:

  1. 计算数据码字、填充码字和长度码字(注意特判s==-1的时候)
  2. 计算校验码字,主要是一个多项式求余

数据码字

  1. 按题意模拟,解析字符串,得到编码值,如果长度是奇数就在加个29
  2. 两两合并
  3. 增加填充码字(使得总个数%w==0)
  4. 增加长度码字

校验码字

  1. 这题难点就在怎么多项式求余,还好数据比较松可以O(N^2)模拟竖式除法
  2. 需要用一个多项式乘法求出gx的系数(求的过程中模929,否则会爆)
  3. fx/gx多项式除法,用一个vector记录对应位置的系数
  4. 注意除法余项的系数取反 ,因为题目给的-rx

gx、fx、rx的系数都分别用vector来存
gx求法
g ( x ) = ( x + 3 ) ∗ ( x + 3 2 ) ∗ . . . g(x)=(x+3)*(x+3^2)*... g(x)=(x+3)(x+32)...
第一步算 A = ( x + 3 ) ∗ ( x + 3 2 ) A=(x+3)*(x+3^2) A=(x+3)(x+32)
第二部算 A = A ∗ ( x + 3 3 ) A=A*(x+3^3) A=A(x+33)

rx求法
模拟竖式除法
每次根据 f ( x ) f(x) f(x) g ( x ) g(x) g(x)的最高次系数计算出当前位的商t,然后计算 f ( x ) f(x) f(x)的余项,直到 f ( x ) f(x) f(x)的最高次小于 g ( x ) g(x) g(x),剩下的fx就是-rx

/*
 * @Email: zhiyyyu@gmail.com
 * @Author: Deng Zehui
 * @Github: nArrow4
 * @Date: 2022-02-23 10:10:43
 */
#include<bits/stdc++.h>
using namespace std;
typedef int Module;
typedef enum{
    UPPER,
    LOWER,
    DIGIT,
} MODE;

vector<Module> modules, g, rx;
int w, s;
int n, k;
const int MOD = 929;
string text;

void getModules(const string& t){
    MODE m = UPPER;
    int n = t.size();
    for (int i = 0; i < n;i++){
        switch(m){
        case UPPER:
            if(islower(t[i])){
                modules.push_back(27);
                modules.push_back(t[i] - 'a');
                m = LOWER;
            } else if(isdigit(t[i])){
                modules.push_back(28);
                modules.push_back(t[i] - '0');
                m = DIGIT;
            } else{
                modules.push_back(t[i] - 'A');
            }
            break;
        case LOWER:            
            if(isupper(t[i])){
                modules.push_back(28);
                modules.push_back(28);
                modules.push_back(t[i] - 'A');
                m = UPPER;
            } else if(isdigit(t[i])){
                modules.push_back(28);
                modules.push_back(t[i] - '0');
                m = DIGIT;
            } else{
                modules.push_back(t[i] - 'a');
            }
            break;
        case DIGIT:
            if(isupper(t[i])){
                modules.push_back(28);
                modules.push_back(t[i] - 'A');
                m = UPPER;
            } else if(islower(t[i])){
                modules.push_back(27);
                modules.push_back(t[i] - 'a');
                m = LOWER;
            } else{
                modules.push_back(t[i] - '0');
            }
            break;
        }
    }
    int size = modules.size();
    if(size&1){
        modules.push_back(29);
        size++;
    }
    for (int i = 0; i < size;i+=2){
        int j = i / 2;
        modules[j] = modules[i] * 30 + modules[i + 1];
    }
    modules.resize(size / 2);

    n = modules.size() + 1;
    k = pow(2, s + 1);
    if(s == -1){
        if(n % w){
            int fill = w - n % w;
            n += fill;
            for (int i = 0; i < fill;i++){
                modules.push_back(900);
            }
        }
    } else{
        if((n + k) % w){
            int fill = w - (n + k) % w;
            n += fill;
            for (int i = 0; i < fill;i++){
                modules.push_back(900);
            }
        }
    }
    modules.insert(modules.begin(), n);
}

// 多项式乘法计算g的系数
// 一项一项乘,vector保留系数
void calcGx(){
    g = vector<Module>(k + 1, 0);
    // (x+3)*(x+3^2)*...
    // g * (x + pow3) = g * x + g * pow3
    g[k] = -3;
    g[k - 1] = 1;
    int pow3 = -9;
    // 一共有k项,前i项相乘有(i+1)个参数(从k往前)
    for (int i = 0; i < k - 1;i++){
        // temp result
        vector<Module> tt(k + 1, 0);
        // copy
        for (int j = k - i - 1; j <= k;j++){
            tt[j] = g[j];
        }
        // g = g * pow3
        for (int j = k - i - 1; j <= k;j++){
            g[j] = (g[j] % MOD) * pow3 % MOD;
        }
        // g = g + tt * x (也就是tt向左移动一位)
        for (int j = k - i - 1; j < k;j++){
            g[j] = (g[j] + tt[j + 1]) % MOD;
        }
        g[k - i - 2] = 1;   // 最高次一定是1
        pow3 *= 3;
        pow3 %= MOD;
    }
}

void calcRx(){
    vector<Module> &gx = g;
    // dx最高n次,但是乘了x^k
    vector<Module> dx(modules.size() + k, 0);
    for (int i = 0; i < modules.size();i++){
        dx[i] = modules[i] % MOD;
    }
    for (int i = 0; i < modules.size();i++){
        int t = dx[i];  // 最高次
        for (int j = 0; j < gx.size();j++){
            dx[i + j] = (dx[i + j] - gx[j] * t % MOD) % MOD;
        }
    }
    for (int i = dx.size() - gx.size() + 1; i < dx.size();i++){
        if(-dx[i] < 0)
            rx.push_back(MOD + (-dx[i] % MOD));
        else
            rx.push_back(-dx[i] % MOD);
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> w >> s;
    cin >> text;
    getModules(text);
    calcGx();
    calcRx();
    
    for (int i = 0; i < modules.size();i++){
        cout << modules[i] << "\n";
    }
    if(s != -1){
        for (int i = 0; i < rx.size();i++){
            cout << rx[i] << "\n";
        }
    }
    return 0;
}
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值