牛客寒假算法基础集训营1 B 炸鸡块君与FIFA22(倍增)

题目大意:

给出一个字符串表示每局游戏的结果,每次询问格式为 (l,r,s),询问若你初始有 s 分,按从左到右的顺序经历了 [l,r] 这一子串的游戏结果后,最终分数是多少。

思路:

对于模 3 意义下相同的初始分数 s1,经历了 [l1,r1] 这一段游戏结果后的变化量是相同的。

我们考虑使用倍增加速查询的过程。

设计状态 go[k][i][j] 表示在初始分数为 k 的情况下,经历了[j,j+2i1]这段游戏后的分数变化量。

每次转移时注意由相应的初始分数状态得到即可。

关于倍增怎样跳着去下一个状态:

对于一个区间 [L,R],区间长度 len 是一个定值,对应一个唯一的二进制表示,每一位的 0/1 就表示我们对于 2i 的选取情况,并且选取情况也是唯一的。

例如 8 的二进制表示为 1000,7 的二进制表示为 0111,如果不选择 23,那么后面就算全选也达不到 23,所以选取情况唯一。

Code:
Copy
int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, q; cin >> n >> q; string s; cin >> s; s = " " + s; auto mod3 = [&](int x) { return (x % 3 + 3) % 3; }; //go[k][i][j] 表示在初始分数为k的情况下,经历了[j, j + 2^i - 1]这段游戏后的分数变化量 vector<vector<vector<int>>> go(3, vector<vector<int>>(24 + 1, vector<int>(n + 1))); for (int j = 1; j <= n; j++) { if (s[j] == 'W') for (int k = 0; k < 3; k++) go[k][0][j] = 1; else if (s[j] == 'L') go[0][0][j] = 0, go[1][0][j] = -1, go[2][0][j] = -1; } for (int i = 1; i <= 24; i++) { for (int j = 1; j <= n; j++) { int m = j + (1 << (i - 1)); if (m <= n) // 没越界 for (int k = 0; k < 3; k++) go[k][i][j] = go[k][i - 1][j] + go[mod3(k + go[k][i - 1][j])][i - 1][m]; } } while (q--) { int l, r, s; cin >> l >> r >> s; int now = l; while (now <= r) { int power = 0; while (now + (1 << power) - 1 <= r) //跳多少 power++; power--; s += go[s % 3][power][now]; //根据分数模3结果访问对应值 now += (1 << power); } cout << s << "\n"; } return 0; }
posted @   Nepenthe8  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示