这道题也卡了好一会,从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;
}