Codeforces Round #337 (Div. 2) E. Alphabet Permutations (线段树lazy 或 set)

大致题意:

一个2e5的字符串STR,最多包含K个字符(K < 10) , 有Q个操作(<2e4) 。

1. 把字符串[L, R]的字符修改成x

2. 给一个K个字符的某个排列s,询问最少重复次数的s连接而成的长串的子序列包含STR

思路1:

因为要修改STR,所以要对STR进行处理,然后要在logn以下的复杂度完成查询操作。

可以注意到最少重复的次数就是STR中相邻的两个字符(ch1, ch2) 在排列s中的位置是ch2在ch1之前,ch2和ch1必然是有两个s串组成。所以可以维护STR相邻字符的对数。用cnt[ch1][ch2]矩阵维护相邻字符ch1ch2的对数。答案就是len(STR) - 相邻对数

由于有修改操作,必须用线段树维护,所以修改的复杂度在O(Qlogn*K*K),查询的复杂度是O(K*K).问题解决


思路2:

同样是维护cnt矩阵,但不用线段树维护,用set维护(http://codeforces.com/contest/610/submission/15053499), 由代码可以看出,当修改某一段字符的时候,暴力维护,然后[L, R]字符已经相同,没有相邻对数了,所以删去set中的[L, R],然后插入两个边界的相邻情况。

这样均摊复杂度是:每次修改操作最多在set里增加2个值,所以整个修改过程最多增加O(n) , 删除的个数不会多于增加的值个数,也是O(n).

所以总复杂度是O(Q * K * K + n) 比 方法一的O(Q * K * K + Qlogn* K * K) 优了logn * K * K级别。


方法一代码:(占用内存比较多,所以用了2倍空间的线段树)

//#pragma comment(linker, "/STACK:1024000000,1024000000")  
#include <iostream>  
#include <cstring>  
#include <cmath>  
#include <queue>  
#include <stack>  
#include <map>  
#include <set>  
#include <string>  
#include <vector>  
#include <cstdio>  
#include <ctime>  
#include <bitset>  
#include <algorithm>  
#define SZ(x) ((int)(x).size())  
#define ALL(v) (v).begin(), (v).end()  
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)  
#define reveach(i, v) for (__typeof((v).rbegin()) i = (v).rbegin(); i != (v).rend(); ++ i)  
#define REP(i,n) for ( int i=1; i<=int(n); i++ )  
#define rep(i,n) for ( int i=0; i< int(n); i++ )  
using namespace std;  
typedef long long ll;  
#define X first  
#define Y second  
#define PB push_back  
#define MP make_pair  
typedef long double ld;
typedef pair<int, int> pii;  
  
template <class T>  
inline bool RD(T &ret) {  
        char c; int sgn;  
        if (c = getchar(), c == EOF) return 0;  
        while (c != '-' && (c<'0' || c>'9')) c = getchar();  
        sgn = (c == '-') ? -1 : 1 , ret = (c == '-') ? 0 : (c - '0');  
        while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');  
        ret *= sgn;  
        return 1;  
}  
template <class T>  
inline void PT(T x) {  
        if (x < 0) putchar('-') ,x = -x;  
        if (x > 9) PT(x / 10);  
        putchar(x % 10 + '0');  
}

const int N = 2e5 + 100;

char s[N];
int n, Q, K;

struct node {
	int cnt[10][10];
	int lv, rv, lazy;
};

struct SegmentTree {
    inline int get_id(int l,int r) {
		return (l + r) | (l != r);
	}
	
	node a[2 * N];

	void up(int l, int r) {
		int mid = (l + r) >> 1;
		int rt = get_id(l, r), ls = get_id(l, mid), rs = get_id(mid + 1, r);
		rep(i, K) 
			rep(j, K) a[rt].cnt[i][j] = a[ls].cnt[i][j] + a[rs].cnt[i][j];
		a[rt].cnt[a[ls].rv][a[rs].lv] ++;
		a[rt].lv = a[ls].lv;
		a[rt].rv = a[rs].rv;
	}

	void down(int l, int r) {
		int mid = (l + r) >> 1;
		int rt = get_id(l, r), ls = get_id(l, mid), rs = get_id(mid + 1, r);
		if(a[rt].lazy == -1) return ;
		memset(a[ls].cnt, 0, sizeof(a[ls].cnt));
		memset(a[rs].cnt, 0, sizeof(a[rs].cnt));
		a[ls].lazy = a[ls].lv = a[ls].rv = a[rs].lazy = a[rs].lv = a[rs].rv = a[rt].lazy;
		a[rt].lazy = -1;
	}

	void build(int l, int r) {
		int rt = get_id(l, r);
		a[rt].lazy = -1;
		if(l == r) {
			a[rt].lv = a[rt].rv = s[l] - 'a';
			return ;
		}
		int mid = (l + r) >> 1;
		build(l, mid);
		build(mid + 1, r);
		up(l, r);
	}

	void update(int L, int R, int val, int l, int r) {
		int rt = get_id(l, r);
		int mid = (l + r) >> 1;
		if( L <= l && r <= R) {
			memset(a[rt].cnt, 0, sizeof(a[rt].cnt));
			a[rt].lazy = a[rt].lv = a[rt].rv = val;
			return ;
		}
		down(l, r);
		if(L <= mid) update(L, R, val, l, mid);
		if(R > mid) update(L, R, val, mid + 1, r);
		up(l, r);
	}

	void debug(int pos, int l, int r) {
		int rt = get_id(l, r);
		if( l == r ) {
			printf("(%c %c)\n", a[rt].lv + 'a', a[rt].rv + 'a');
			return ;
		}
		down(l, r);
		int mid = (l + r) >> 1;
		if(pos <= mid) debug(pos, l, mid);
		else debug(pos, mid + 1, r);
	}
}A;


int main() {
	cin >> n >> Q >> K;
	scanf("%s", s + 1);
	A.build(1, n);
	REP(i, Q) {
		int op;
		RD(op);
		if(op == 1) {
			int l, r;
			char val[5];
			RD(l), RD(r);
			scanf("%s", val);
			A.update(l, r, val[0] - 'a', 1, n);
		} else {
			scanf("%s", s);
			int ans = n;
			for(int i = 0; s[i]; i ++)
				for(int j = i + 1; s[j]; j ++) 
					ans -= A.a[A.get_id(1, n)].cnt[s[i] - 'a'][s[j] - 'a'];
			printf("%d\n", ans);
		}
	//	REP(i, n) A.debug(i, 1, n);
	}
}


方法二代码:http://codeforces.com/contest/610/submission/15053499


E. Alphabet Permutations
time limit per test
1 second
memory limit per test
512 megabytes
input
standard input
output
standard output

You are given a string s of length n, consisting of first k lowercase English letters.

We define a c-repeat of some string q as a string, consisting of c copies of the string q. For example, string "acbacbacbacb" is a 4-repeat of the string "acb".

Let's say that string a contains string b as a subsequence, if string b can be obtained from a by erasing some symbols.

Let p be a string that represents some permutation of the first k lowercase English letters. We define function d(p) as the smallest integer such that a d(p)-repeat of the string p contains string s as a subsequence.

There are m operations of one of two types that can be applied to string s:

  1. Replace all characters at positions from li to ri by a character ci.
  2. For the given p, that is a permutation of first k lowercase English letters, find the value of function d(p).

All operations are performed sequentially, in the order they appear in the input. Your task is to determine the values of functiond(p) for all operations of the second type.

Input

The first line contains three positive integers nm and k (1 ≤ n ≤ 200 000, 1 ≤ m ≤ 20000, 1 ≤ k ≤ 10) — the length of the strings, the number of operations and the size of the alphabet respectively. The second line contains the string s itself.

Each of the following lines m contains a description of some operation:

  1. Operation of the first type starts with 1 followed by a triple liri and ci, that denotes replacement of all characters at positions from li to ri by character ci (1 ≤ li ≤ ri ≤ nci is one of the first k lowercase English letters).
  2. Operation of the second type starts with 2 followed by a permutation of the first k lowercase English letters.
Output

For each query of the second type the value of function d(p).

Sample test(s)
input
7 4 3
abacaba
1 3 5 b
2 abc
1 4 4 c
2 cba
output
6
5
Note

After the first operation the string s will be abbbbba.

In the second operation the answer is 6-repeat of abcABcaBcaBcaBcaBcAbc.

After the third operation the string s will be abbcbba.

In the fourth operation the answer is 5-repeat of cbacbAcBacBaCBacBA.

Uppercase letters means the occurrences of symbols from the string s.



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值