炸鸡块君与FIFA22(ST表)

题目链接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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值