NOIP模拟(10.27)T1 寿司

寿司

题目背景:

10.27 NOIP模拟T1

分析:暴力

 

老子有句喵喵喵真的非常想讲······

觉得今天T1最难的一定不是只有我,T1代码最长的也一定不是只有我,总之这个真的叫T1吗,不过给我留了50分我还真是谢谢你了······

直接讲题吧,考虑如果我们先不考虑成环的问题,那么很显然的我们需要将B给移到两边,或者R移到两边,我们这里直接说R吧,显然,这样做的答案,应该是,每一个被移到左边去的R左边原来的B的个数,每一个被移到右边去的R右边原来的B的个数,那么很显然的,我们最好的方式是将,第(B的总个数 + 1) / 2B(以下将第(B的总个数 + 1) / 2B的位置简称为pos)左边的R全部移到左边,右边的R移到右边,现在我们就有了一种很暴力的O(n2)做法了,就是将这个串的n个循环同构串都这么找到中间的B然后统计一下答案,取最小就好了,显然我们看看数据范围,还是停止了这种naïve的想法······考虑如何在循环同构的过程中维护第(B的总个数 + 1) / 2B所在的位置和当前的答案,考虑每一次更改我们都将当前字符串的第一个字符移到最后去,假如这一个字符为B,那么如果我们原来的pos不移动,那么就是原来pos左边的所有R的贡献都会减少1pos右边的都会加上1,这样就维护了答案,再考虑如何移动pos,显然,我们只需要往后面找到下一个B所在的位置就是新的pos了,那么在移动过程中就有很多的R从原来的pos右边,变成了pos左边,那么我们减去它右边的B的数量,加上它左边的B的数量就可以了。这些操作都可以通过维护RB的前缀和来比较方便的完成。复杂度O(Tn)

Source

/*
	created by scarlyw
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <cctype>
#include <queue>
#include <vector>
#include <ctime>

const int MAXN = 2000000 + 10;
const long long INF = 1000000000000000000;
int t, len, n;
int lb[MAXN], lr[MAXN], rb[MAXN], rr[MAXN];
char s[MAXN];

int main() {
	std::ios::sync_with_stdio(NULL);
	std::cin.tie(NULL), std::cout.tie(NULL);
	std::cin >> t;
	while (t--) {
		std::cin >> (s + 1), len = strlen(s + 1);
		long long fans1 = INF;
		for (int i = 1; i <= len; ++i) s[i + len] = s[i];
		n = len, len *= 2;
		for (int i = 1; i <= len; ++i) {
			lb[i] = lb[i - 1], lr[i] = lr[i - 1];
			if (s[i] == 'B') lb[i]++;
			else lr[i]++;
		}
		for (int i = len; i >= 1; --i) {
			rb[i] = rb[i + 1], rr[i] = rr[i + 1];
			if (s[i] == 'B') rb[i]++;
			else rr[i]++;
		}
		long long ans1 = 0;
		int pos = (lb[n] + 1) / 2, p = -1;
		for (int i = 1; i <= n; ++i) {
			if (lb[i] == pos) {
				p = i; 
				for (int j = n; j >= i; --j)
					if (s[j] == 'R') ans1 += (long long)(rb[j] - rb[n + 1]);
				break ;
			}
			if (s[i] == 'R') ans1 += (long long)lb[i];
		}
		int head = 1, tail = n;
		fans1 = ans1;
		while (head <= n) {
			if (s[head] == 'B') {
				ans1 -= lr[p] - lr[head - 1];
				ans1 += rr[p] - rr[++tail], ++head;
				while (s[++p] != 'B') {
					ans1 += (long long)(lb[p] - lb[head - 1]);
					ans1 -= (long long)(rb[p] - rb[tail + 1]);
				}
			} else head++, tail++;
			fans1 = std::min(fans1, ans1);
		}
		std::cout << fans1 << '\n';
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值