zoukankan      html  css  js  c++  java
  • 【ICPC】ICPC2017World Final_K_Tarot Sham Boast_结论/证明/字符串

    链接

    ICPC World Final 2017 (codeforces gym)

    题解

    • 网上查题解的时候看到了一道其他题目的结论:“根据歌唱王国的结论,模式串 S 在随机文本串中第一次出现的位置期望为(sum_{bin 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;
    }
    
  • 相关阅读:
    Unity3D串口处理
    Crixalis's Equipment 杭电 (设计贪心算法,比较巧妙,我用的是结构体排序)
    杭电 看归并排序和快速排序
    杭电acm 排名 (涉及到结构体排序)
    程序在计算机的内存(看到了一篇博客,解决了我的疑惑)
    贪心算法and排序 杭电一题的启发
    辗转相除法 杭电acm
    单调队列
    用栈的思想处理字符串倒置问题更清晰
    VS的哪些事儿之二
  • 原文地址:https://www.cnblogs.com/czyarl/p/13982831.html
Copyright © 2011-2022 走看看