移动端没做适配,所以看起来十分诡异是正常的

【ICPC】ICPC2017World Final_K_Tarot Sham Boast_结论/证明/字符串

链接

ICPC World Final 2017 (codeforces gym)

题解

  • 网上查题解的时候看到了一道其他题目的结论:“根据歌唱王国的结论,模式串 S 在随机文本串中第一次出现的位置期望为\(\sum_{b\in B}|\sum|b\),其中\(B\)\(S\)的Border长度集合。”
    • 这个结论或许能直接感性上提示出这道题该怎么做。
    • 我们直接考虑将串S的所有Border长度从大到小排成序列\(B^{(S)}\),我们发现显然\(B^{(S)}\)字典序越大,出现的概率不会变小。
    • 但是什么情况下出现概率相等?我们考虑容斥的过程,发现那些长度小于\(2|S|-n\)的Border压根不会对概率产生影响。所以这些Border我们应该将其踢掉(下文中我们的\(B^{(S)}\)就直接用剔除过无用Border的集合了。)。剩下的东西的字典序相等概率就一定相等。
  • 我们有了这样一个结论:我们将串S的所有长度大于等于\(2|S|-n\)的Border长度从大到小排成序列\(B^{(S)}\),我们再记串\(S\)在字符集大小为\(k\),长度为\(n\)的随机串中出现的概率为\(P_{n,k}^{(S)}\),简记为\(P^{(S)}\)。我们定义\(B^{(S)}\)间的偏序关系为字典序,则\(P^{(S)}\)间的偏序关系和\(B^{(S)}\)间的偏序关系完全相同。
  • 至此,这道题已经可以做完了。ACM赛场上一交就过,OI赛场上也可以通过对拍大致验证。
  • 但是,怎么证呢?
  • 这里曾经有一个证明,可惜他假了。

代码

#include<bits/stdc++.h>
#define LL long long
#define MAXN 101000
using namespace std;
template<typename T> void Read(T &cn)
{
	char c; int sig = 1;
	while(!isdigit(c = getchar())) if(c == '-') sig = 0;
	if(sig) {cn = c-48; while(isdigit(c = getchar())) cn = cn*10+c-48; }
	else    {cn = 48-c; while(isdigit(c = getchar())) cn = cn*10+48-c; }
}
template<typename T> void Write(T cn)
{
	int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
	if(cn < 0 || cx < 0) {putchar('-'); cn = 0-cn; cx = 0-cx; }
	while(cn)cm = cm*10+cn%10,cn/=10,wei++;
	while(wei--)putchar(cm%10+48),cm/=10;
	putchar(cx+48);
}
template<typename T> void WriteL(T cn) {Write(cn); puts(""); }
template<typename T> void WriteS(T cn) {Write(cn); putchar(' '); }
template<typename T> void Max(T &cn, T cm) {cn = cn < cm ? cm : cn; }
template<typename T> void Min(T &cn, T cm) {cn = cn < cm ? cn : cm; }
struct Str{
	int b[MAXN+1], ne[MAXN+1];
	char c[MAXN+1];
	int clen, blen;
	int pos;
	void getit(int cn)
	{
		pos = cn;
		while(!isalpha(c[1] = getchar())); clen = 1;
		while(isalpha(c[++clen] = getchar())); clen--;
	}
	void get_b(int cn)
	{
		ne[0] = ne[1] = 0;
		for(int i = 2;i<=clen;i++)
		{
			ne[i] = ne[i-1];
			while(ne[i] && c[i] != c[ne[i]+1]) ne[i] = ne[ne[i]];
			if(c[i] == c[ne[i]+1]) ne[i]++;
		}
		blen = 0; int xian = clen;
		while(xian) b[++blen] = xian, xian = ne[xian];
		while(blen && b[blen] < 2*clen-cn) blen--;
	}
	inline friend bool operator <(Str &A, Str &B)
	{
		int lin = min(A.blen, B.blen);
		for(int i = 1;i<=lin;i++) if(A.b[i] != B.b[i]) return A.b[i] < B.b[i];
		if(A.blen != B.blen) return A.blen < B.blen;
		return A.pos < B.pos;
	}
	void outit() {for(int i = 1;i<=clen;i++) putchar(c[i]); puts(""); }
};
int n,s;
Str a[11];
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	Read(n); Read(s);
	for(int i = 1;i<=s;i++) a[i].getit(i), a[i].get_b(n);
	sort(a+1, a+s+1);
	for(int i = 1;i<=s;i++) a[i].outit();
	return 0;
}
posted @ 2020-11-15 22:45  czyarl  阅读(239)  评论(0编辑  收藏  举报