bzoj3770 疯狂的限制

  疯狂的限制

题目背景:

bzoj3770

分析:算是暴力吧······

 

本来是在做DP来着,然后看到这道题就一起做掉了······做了这道题终于发现,vector是多么有用的东西······我们枚举右端点,那么每次往右移动一个,相当于加入了一个字符,假设当前位置为cur tot[i]表示i ~ cur所形成的子串满足了多少条件,那么新加进来的s[cur + 1]tot的影响其实非常小,他影响的就是所有字符为s[cur + 1]的限制的贡献,(c[i] == s[cur + 1]),如果当前位置cur + 1, 是第ks[cur + 1]出现的位置,那么影响到的贡献位置就是第k - l[i]s[cur + 1]和第k - l[i] + 1s[cur + 1]之间。还有第k - r[i] - 1和第k - r[i]s[cur + 1], 那么我们要做的就是快速找到每一个限制字符为s[cur + 1]的限制,和上面所说的影响到的s[cur + 1]出现的位置,这两者都可以很快的通过vector找到,然后暴力一发,注意边界即可。

注意:

1、关于边界

我们可以预先在存储每一个字符出现位置的vector中预先放入-1,这样就可以很方便的更改开头一段的贡献了

2、关于0

因为可能某些限制的l[i] == 0统计的时候可能会出现问题,所以需要单独进行考虑。

 

Source

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

const int MAXN = 100000 + 10;
const int ALP = 26;
const int MAXM = 500 + 10;

char c;
char s[MAXN];
int k, len, cnt, ans, l_limit, r_limit;
int q[MAXM][3], tot[MAXN];
long long final_ans;
std::vector<int> query[ALP];
std::vector<int> pos[ALP];

inline void read_in() {
	scanf("%s", s), len = strlen(s), cnt = 0;
	scanf("%d%d%d", &k, &l_limit, &r_limit);
	for (int i = 1; i <= k; ++i) {
		static char c[5];
		scanf("%s%d%d", c, &q[i][1], &q[i][2]);
		q[i][0] = c[0] - 'a', query[q[i][0]].push_back(i);
		cnt += (q[i][1] == 0);
	}
}

inline void solve() {
	for (int i = 0; i < ALP; ++i) pos[i].push_back(-1);
	int ans = 0;
	for (int i = 0; i < len; ++i) {
		int c = s[i] - 'a';
		pos[c].push_back(i), tot[i] += cnt;
		ans += (tot[i] >= l_limit && tot[i] <= r_limit);
		for (int k = query[c].size() - 1; k >= 0; --k) {
			int p = query[c][k], size = pos[c].size() - 1;
			if (size >= q[p][1] && q[p][1] != 0)
				for (int j = pos[c][size - q[p][1]] + 1; 
					j <= pos[c][size - q[p][1] + 1]; ++j) {
					tot[j]++, (tot[j] == l_limit) ? (ans++) : 
						(tot[j] == r_limit + 1 ? ans-- : 0);
				}
			if (size > q[p][2])
				for (int j = pos[c][size - q[p][2] - 1] + 1; 
					j <= pos[c][size - q[p][2]]; ++j) {
					tot[j]--, (tot[j] == l_limit - 1) ? (ans--) :
							(tot[j] == r_limit ? ans++ : 0); 
				}
		}
		final_ans += (long long)ans;
	}
	printf("%lld", final_ans);
}

int main() {
	read_in();
	solve();
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值