Live2D

题解 游戏

link

Description

给出两个字符串 \(s_1,s_2\),对于任意一个长度 \(k\),问从两个字符串中随机各选一个长度为 \(k\) 的子序列 A,B ,A 字典序大于 B,A 字典序等于 B,A 的字典序小于 B 的概率。

\(n,m\le 2\times 10^5\)

Solution

可以想到对于一个长度 \(k\),我们其实只需要计算 \(A\ge B\) 的个数以及 \(A\le B\) 的个数,然后就可以算出来了。

下面以 \(A\ge B\) 为例考虑计算。考虑将两个字符串接在一起(中间需要加入特殊字符)做 SA,那么对于 \(s_1\) 的后缀 \(a\)\(s_2\) 的后缀 \(b\),如果 \(\text{rk}_a>\text{rk}_b\),那么 \(k\) 取任意值都满足,否则,\(k\le \text{lcp}(a,b)\) 的时候满足。

考虑如何计算,发现第一种情况可以直接二维偏序进行计算,第二种可以直接考虑枚举最小值。

复杂度可以做到 \(\Theta(n\log n)\),但是我比较懒,所以我的 SA build 部分写的是 \(\Theta(n\log^2n)\) 的。

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define int long long
#define MAXN 400005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

int n,m,len;
char S[MAXN],s1[MAXN],s2[MAXN];

#define ull unsigned long long
#define seed 131

ull has[MAXN],pw[MAXN];
int sa[MAXN],rk[MAXN],st[MAXN][21];

ull gethash (int l,int r){
	return has[r] - has[l - 1] * pw[r - l + 1];
}

int getlen (int t1,int t2){
	int l = 1,r = min (len - t1 + 1,len - t2 + 1),ans = 0;
	while (l <= r){
		int mid = l + r >> 1;
		if (gethash (t1,t1 + mid - 1) == gethash (t2,t2 + mid - 1)) ans = mid,l = mid + 1;
		else r = mid - 1;
	}
	return ans;
}

bool cmp (int t1,int t2){
	int t = getlen (t1,t2);
	if (t1 + t - 1 == len) return 1;
	else if (t2 + t - 1 == len) return 0;
	else return S[t1 + t] < S[t2 + t];
}

int det1[MAXN],det2[MAXN];

void print (int x,int y){
	int t = __gcd (x,y);
	write (x / t),putchar ('/'),write (y / t);
}

int query (int l,int r){
	int k = log2 (r - l + 1);
	return min (st[l][k],st[r - (1 << k) + 1][k]);
}

void build (){
	pw[0] = 1;
	for (Int i = 1;i <= len;++ i) has[i] = has[i - 1] * seed + S[i] - 'a' + 1,pw[i] = pw[i - 1] * seed,sa[i] = i;
	sort (sa + 1,sa + len + 1,cmp);
	for (Int i = 1;i <= len;++ i) rk[sa[i]] = i;
	for (Int i = 2;i <= len;++ i) st[i][0] = getlen (sa[i - 1],sa[i]);
	for (Int j = 1;(1 << j) <= len;++ j)
		for (Int i = 1;i + (1 << j) - 1 <= len;++ i)
			st[i][j] = min (st[i][j - 1],st[i + (1 << j - 1)][j - 1]);
}

namespace Subtask1{
	struct Bit_Tree{
		int sum[MAXN];
		int lowbit (int x){return x & (-x);}
		void modify (int x,int v){for (Int i = x;i <= len;i += lowbit (i)) sum[i] += v;}
		int query (int x){int res = 0;for (Int i = x;i;i -= lowbit (i)) res += sum[i];return res;}
		int query (int l,int r){return query (r) - query (l - 1);}
	}ta,tb;
	void Work (){
		for (Int i = 1,j = 1;i <= n || j <= m;)
			if (i <= n && (j > m || n - i + 1 >= m - j + 1)){
				int cnt = tb.query (rk[i] + 1,len);
				det1[1] += cnt,det1[n - i + 2] -= cnt;
				cnt = tb.query (1,rk[i]);
				det2[1] += cnt,det2[n - i + 2] -= cnt;
				ta.modify (rk[i],1),++ i;
			}
			else{
				int cnt = ta.query (rk[n + j + 1] + 1,len);
				det2[1] += cnt,det2[m - j + 2] -= cnt;
				cnt = ta.query (1,rk[n + j + 1]);
				det1[1] += cnt,det1[m - j + 2] -= cnt;
				tb.modify (rk[n + j + 1],1),++ j; 
			}
	}
}

namespace Subtask2{
	int preA[MAXN],preB[MAXN];
	void Work (){
		for (Int i = 1;i <= len;++ i) preA[i] = preA[i - 1] + (sa[i] <= n),preB[i] = preB[i - 1] + (sa[i] > n + 1);
//		cout << preA[len] << " , " << preB[len] << endl;
		for (Int i = 2;i <= len;++ i){
			int l = 2,r = i - 1,res1 = i;
			while (l <= r){
				int mid = l + r >> 1;
				if (query (mid,i - 1) >= st[i][0]) res1 = mid,r = mid - 1;
				else l = mid + 1;
			}
			l = i + 1,r = len;int res2 = i;
			while (l <= r){
				int mid = l + r >> 1;
				if (query (i + 1,mid) > st[i][0]) res2 = mid,l = mid + 1;
				else r = mid - 1;
			}
			int lA = (preA[i - 1] - preA[res1 - 2]),lB = (preB[i - 1] - preB[res1 - 2]),rA = (preA[res2] - preA[i - 1]),rB = (preB[res2] - preB[i - 1]);
			det2[1] += lA * rB,det2[st[i][0] + 1] -= lA * rB;
			det1[1] += lB * rA,det1[st[i][0] + 1] -= lB * rA;
		}
	}
}

signed main(){
	freopen ("game.in","r",stdin);
	freopen ("game.out","w",stdout);
	scanf ("%s%s",s1 + 1,s2 + 1),n = strlen (s1 + 1),m = strlen (s2 + 1);
	for (Int i = 1;i <= n;++ i) S[++ len] = s1[i];S[++ len] = 'a' + 27;
	for (Int i = 1;i <= m;++ i) S[++ len] = s2[i];
	build ();
	Subtask1::Work (),Subtask2::Work ();
	for (Int i = 1;i <= min (n,m);++ i) det1[i] += det1[i - 1],det2[i] += det2[i - 1];
	for (Int i = 1;i <= min (n,m);++ i){
		int s1 = det1[i],s3 = det2[i],all = (n - i + 1) * (m - i + 1),s2 = s1 + s3 - all;
		print (s1 - s2,all),putchar (' '),print (s2,all),putchar (' '),print (s3 - s2,all),putchar ('\n');
	}
 	return 0;
}
posted @ 2021-10-14 19:35  Dark_Romance  阅读(48)  评论(0编辑  收藏  举报