从去年勉强拿到一个铜牌,到今年的勉强拿到一个金牌,对于我而言,究竟有多少长进呢。
一直以来我并不认为我曾拥有什么惊人的编程的天赋,最多是说比很多人好一些罢了。
放到程序竞赛里更是如此,愈是了解,愈是意识到自己的水平之低劣。
动态规划之类的算法我掌握得可以说非常非常蹩脚,博弈论数论这种就属于看到直接跳掉的程度。搞了这么久,还是只会套套板子,写写模拟题之类的。
说起来,这回的省赛我只给这题提供了一些辅助,写了个暴力的版本来对拍debug以外,剩下的就只有给H题提供了一个会TLE的思路了,感觉完全是队友给力才拿到的金牌。
虽然这个题场上是队友写的,但是当时反复讨论,解题思路还是非常清晰的,也想着自己写个看看。另外网上对于该题的题解,放眼望去全是数位dp,这个风气很不好啊,什么东西都往dp上搞(雾
明明可以模拟过去的(大雾
本题的大致题意是有一个8位的7段数码管,给定它的初始状态
与显示时长
,当显示溢出后归0并继续,问这个过程一共要花费多少能量,各7段管的显示所需能量为所显示的数字的段数。
模拟的思路就是考虑每一位对于答案的贡献。显然当数字很大时,中间会出现很多的循环显示,那么只要把中间循环的大头解决掉的话,剩下的就是结尾那些各位不足一个循环的部分了,这里只要想清楚每个数字是在什么情况下变更就不容易写错了。
更多的解释详见代码注释,我想应该解释得足够清楚了。
#include <algorithm>
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
inline int todec(char c)
{
return c >= 'A' ? c - 'A' + 10 : c - '0';
}
inline long long todec(string hex)
{
if (hex.size() == 0) return 0;
long long ret = 0;
for(auto iter = hex.begin(); iter != hex.end(); ++iter)
{
ret = ret * 16 + todec(*iter);
}
return ret;
}
int energy[] = {
6,2,5,5,4,5,6,3,7,6,6,5,4,5,5,4,
6,2,5,5,4,5,6,3,7,6,6,5,4,5,5,4
};
const int energy_per_round = 78;
const int digit_count = 16;
const long double one = 1.0;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T; cin >> T;
while (T--)
{
int n; string s;
cin >> n >> s;
long long dur_per_digit = 1;
long long ans = 0;
for(int i = 7; i >= 0; --i)
{
//计算整段循环的
long long dur_per_loop = dur_per_digit * digit_count;
long long loop_cnt = n / dur_per_loop;
long long loop_energy_consume = loop_cnt * energy_per_round * dur_per_digit;
ans += loop_energy_consume;
//计算剩余不足一循环的部分
//其中第一个值的持续时长为全F与其右边的子串的差 或 剩余时间
//剩下的除最后一个均为dur_per_digit
///处理首个值
int curr = todec(s[i]);
//该位右边的子串距离进位所需时间
long long delta = todec(string(7 - i, 'F')) - todec(s.substr(i + 1)) + 1;
long long rest_time = n - loop_cnt * dur_per_loop;
delta = min(rest_time, delta);//判断次数是否满足进位
ans += energy[curr++] * delta;
rest_time -= delta;//更新剩余时间
if (rest_time == 0)
{
dur_per_digit *= digit_count;
continue;//即只有一个值
}
//若rest_cnt为0则剩下的时间都是最后一个的
long long rest_cnt = ceil(rest_time*one / dur_per_digit);//剩余的字符数
long long last_time;
if (rest_cnt == 0) last_time = rest_time;
else last_time = rest_time - (rest_cnt - 1)*dur_per_digit;
///处理中间值
for(long long j = 0; j < rest_cnt - 1; ++j)
{
ans += energy[curr++] * dur_per_digit;
}
///处理最后一个值
ans += energy[curr] * last_time;
dur_per_digit *= digit_count;
}
cout << ans << "\n";
}
}