CCF-CSP 202112-3 登机牌条码

本文介绍了在C++编程中,通过数据类型调整、取模操作和自定义阶乘函数等方法,成功将代码性能从60分提升至100分的具体步骤。
摘要由CSDN通过智能技术生成

这道题也卡了好一会,从60分一路优化到100分,主要就是1.将可能会爆的数据从int改成long long 2. 能取模的地方全都取模,特别是算gx那块(前两条改完从60到80) 3.自己写阶乘函数,每乘一次取一次模(改完就从80到100了)。剩下的部分按部就班选择合适的结构一步步模拟就好,其实不难,代码也不是很长,但做起来有点花时间。

#include <bits/stdc++.h>
using namespace std;
vector<long long>a;

long long b[10010] = {0};
map<int, long long>gx;
long long powmyself(int x, int y) { //x的y次方,每次计算都取模
	long long answer = 1;
	for (int p = 1; p <= y; p++)
		answer = answer * x % 929;
	return answer;
}
map<int, long long> multiply(map<int, long long>x, long long n) {
	//n就是乘x - 3 ^n
	long long kn, c;
	map<int, long long>temp;
	for (auto i : x) { //次数加一,项数相乘//次数不变,项数乘-3^n
		kn = i.first;//这是次数
		c = i.second;//这是项数
		long long s = powmyself(3, n) % 929L;//自己写阶乘函数!每乘一次取一次模
		long long t = (-c * s) % 929L;
		temp.insert(pair<int, long long>(kn, t % 929L));
	}
	for (auto i : x) {
		kn = i.first;//这是次数
		c = i.second;//这是项数
		temp[kn + 1] = (c + temp[kn + 1]) % 929L;
	}
	return temp;
}

void judge(char f, char n) {
	if (f >= 'A' && f <= 'Z' && n >= 'a' && n <= 'z') //大写转小写
		a.push_back(27);
	if (f >= 'a' && f <= 'z' && n >= 'A' && n <= 'Z') { //小写转大写
		a.push_back(28);
		a.push_back(28);
	}
	if (f >= 'A' && f <= 'Z' && n >= '0' && n <= '9') //大写转数字
		a.push_back(28);
	if (f >= '0' && f <= '9' && n >= 'A' && n <= 'Z') //数字转大写
		a.push_back(28);
	if (f >= 'a' && f <= 'z' && n >= '0' && n <= '9') //小写转数字
		a.push_back(28);
	if (f >= '0' && f <= '9' && n >= 'a' && n <= 'z') //数字转小写
		a.push_back(27);
}

int main() {
	long long w, s; //每行能容纳的码字数,校验级别
	cin >> w >> s;
	string temp;
	cin >> temp;
	char f = 'A';
	for (register int i = 0; i < temp.size(); i++) {
		char n = temp[i];
		judge(f, n);
		long long real = 0;
		if (n >= '0' && n <= '9')
			real = n - '0';
		else if (n >= 'a' && n <= 'z')
			real = n - 'a';
		else//当前是大写字母
			real = n - 'A';
		a.push_back(real);
		f = n;
	}
	if (a.size() % 2 != 0)
		a.push_back(29);
	//计算数据码字
	int check = s == -1 ? 0 : pow(2, (s + 1));//校验码位数,也是题目中的k
	int length = 1 + a.size() / 2 + check;
	int fill = 0;
	if (length % w != 0)
		fill = w - length % w; //填充码字的位数
	length = fill + 1 + a.size() / 2;//就是题目中的n
	b[0] = length;
	int number = 1;
	for (register int i = 0; i < a.size(); i = i + 2) {
		b[number] = a[i] * 30 + a[i + 1];
		number++;
	}
	for (register int i = a.size() / 2 + 1; i <= a.size() / 2 + fill; i++)
		b[i] = 900;
	//cout << length << endl;
	//现在k(check),n(length),dx,gx都有了,找qx
	//分析一下,dx乘x的k次方是x的k+n-1次方,右边gx是k次方,rx不大于k-1次方
	//因此qx得有n-1次方,还得保证与gx相乘后至少把左边的k+n-1次方项到k次方项全消干净
	//左边除gx就行了,把余数拿出来当-rx。b里b[0]存的是dn-1,对应x为k+n-1次方,bn-1存的是d0,对应x的k次方
	gx.insert(pair<int, long long>(0, 1));
	for (register int n1 = 1; n1 <= check; n1++)
		gx = multiply(gx, n1);//现在的gx就是要求的gx
	for (register int i = 0; i < length; i++)
		cout << b[i] << endl;
	int k;
	int i = 0;//从b0开始,k+n-1次方
	map<int, long long>::reverse_iterator it;
	for (i; i < length; i++) { //i表示b的下标
		it = gx.rbegin();//从gx最高项开始,k次方
		//long long j = 0;
		k = check + length - 1 - i; //b实际的次数
		int resultk = k - it->first;
		long long resultc = b[i] / (it->second); //求出本次计算的商
		for (it; it != gx.rend(); it++) { //将商项与gx相乘,用b减掉
			int tempk = it->first; //对应的系数
			long long tempc = (it->second) % 929; //对应的项数
			int ansk = tempk + resultk;
			long long ansc = tempc * resultc % 929;
			b[check + length - 1 - ansk] = (b[check + length - 1 - ansk] - ansc ) % 929 ;
		}
	}
	for (register int i = length; i <= length + k - 1; i++) {
		cout << ((-b[i]) % 929 + 929) % 929 << endl;
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值