题目链接https://ac.nowcoder.com/acm/contest/23106/B
题目描述
热爱足球(仅限游戏)的炸鸡块君最近购买了FIFA22,并且沉迷于FIFA22的Rivals排位上分。
在该排位系统中,每局游戏可能有胜利(用W表示)、失败(用L表示)、平局(用D表示)三种结果,胜利将使得排位分加一、失败使排位分减一、平局使排位分不变。特别地,该排位系统有着存档点机制,其可以简化的描述为:若你当前的排位分是333的整倍数(包括0倍),则若下一局游戏失败,你的排位分将不变(而不是减一)。
现在,给定一个游戏结果字符串和若干次询问,你需要回答这些询问。
每次询问格式为(l,r,s),询问若你初始有s分,按从左到右的顺序经历了[l,r]这一子串的游戏结果后,最终分数是多少。
输入描述:
输入第一行输入两个整数n,q(1≤n,q≤2×10^5),表示游戏结果字符串长度与询问次数。
第二行输入一个字符串,表示游戏结果字符串,保证之中只含有W、L、D三种字符。
接下来q行,每行三个数l,r,s(1≤l,r≤n,0≤s≤10^9)代表一组询问,询问含义如题面所述。
输出描述:
对于每个询问输出一个整数表示答案
输入
10 7 WLDLWWLLLD 2 6 0 2 6 1 2 6 2 2 6 9 1 7 0 7 10 10 10 10 100
输出
2 2 2 11 1 9 100
ST表!
•注意到起始分数若在%3意义下相等,即经历[𝑙, 𝑟]一段后分数的变化量是一个定值;
• 定义𝑠𝑡 [3][200010][21]之中𝑠𝑡 [k] [i] [𝑗]表示在初始分数为𝑘的情况 下经历了[𝑖, 𝑖 + 2^ 𝑗 − 1]一段儿游戏后分数的变化量;
• 假设预处理出了𝑠𝑡,则对于一次询问,可以先将其初始分数𝑠对3 取模,然后按照倍增的套路从𝑙跳若干个2的次幂跳到𝑟,跳的时 候要按照分数对3取模的结果来决定访问哪个𝑠𝑡值。
• 𝑠𝑡 [k][i][𝑗]如何预处理:
• 首先,按照字符串内容初始化𝑗 = 0的情况;
• 然后, 𝑠𝑡 [k][i] [𝑗]由𝑠𝑡[k][i] [𝑗 − 1]和𝑠𝑡[k][p][𝑗 − 1]计算得到,之中 𝑝 = 𝑖 + 2^ 𝑗−1 。
• 转移方程:
•𝑠𝑡 [k][i] [𝑗] =𝑠𝑡[k][i] [𝑗 − 1] + 𝑠𝑡[ (𝑘 + 𝑠𝑡 [k][i][j-1])%3][𝑝][𝑗 − 1] • 之中 (𝑘 + 𝑠𝑡 [k][i][j-1])%3表示若在𝑖处初始分数为𝑘,那么到了𝑝 处时分数对3取模得多少
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int f[3][N][21];
char s[N];
int mod(int x)
{
return (x % 3 + 3) % 3;
}
int main()
{
int n, q;
scanf("%d%d", &n, &q);
scanf("%s", s + 1);
for(int j = 0; j <= 20; j++)
for(int i = 1; i <= n; i++)
{
if(!j)
{
if(s[i] == 'W')
f[0][i][j] = f[1][i][j] = f[2][i][j] = 1;
if(s[i] == 'L')
{
f[0][i][j] = 0;
f[1][i][j] = f[2][i][j] = -1;
}
if(s[i] == 'D')
f[0][i][j] = f[1][i][j] = f[2][i][j] = 0;
}
else
{
int t = 1 << (j - 1);
if(i + t > n)
{
f[0][i][j] = f[0][i][j - 1];
f[1][i][j] = f[1][i][j - 1];
f[2][i][j] = f[2][i][j - 1];
}
else
{
f[0][i][j] = f[0][i][j - 1] + f[mod(f[0][i][j - 1])][i + t][j - 1];
f[1][i][j] = f[1][i][j - 1] + f[mod(1 + f[1][i][j - 1])][i + t][j - 1];
f[2][i][j] = f[2][i][j - 1] + f[mod(2 + f[2][i][j - 1])][i + t][j - 1];
}
}
}
int ans = 0;
for(int i = 1; i <= q; i++)
{
int l, r, s;
scanf("%d%d%d", &l, &r, &s);
int pos = l;
while(pos <= r)
{
int j = 0;
while(pos + (1 << j) - 1 <= r)
j++;
j--;
s += f[s % 3][pos][j];
pos += (1 << j);
}
printf("%d\n", s);
}
return 0;
}