[学习笔记] 量产毒瘤题 - 纳什均衡 - 后缀数组 - 学习笔记

题目大意:给你一个字符串,两个玩家分别独立同时的选择一个后缀,并且计算两个后缀的最长公共前缀。第一个玩家希望它尽量大,另一个希望尽量小,问最后期望多长。
题解:
前缀知识:纳什均衡
纳什均衡毫无疑问是个很复杂的问题,我们之看一个特例来了解一下。
ckw和妹子玩游戏(大雾),他跟妹子说我们同时独立的写出一个0或者写出一个1,若我们都写出了0,我给你a块钱;若都写出了1,我给你b块;若我0你1,你给我c块,否则你给我d块。
那么考虑我用x的概率写0,1-x的概率写1。
那么站在我的角度思考妹子的立场,若妹子能通过改变策略使得我的期望收益发生变化,那我钦定的x一定不优。
因此,当 − a x + d ( 1 − x ) = x c + ( − b ) ( 1 − x ) -ax+d(1-x)=xc+(-b)(1-x) ax+d(1x)=xc+(b)(1x)时x最优。
解出x即可,y同理。

那么这个题我们建SA后在后缀数组上分治,考虑solve(l,r)表示之考虑其上l~r的后缀的决策的答案,那么找到h最小的位置,然后设x表示第一个人决策在左边的概率,解出即可。

#include
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<
#define sp <<" "
#define ln <
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=100010,LOG=20;
namespace SA{
	int a[N],v[N],cnt[N],qwq1[N<<1],qwq2[N<<1],sa[N],h[N],rk[N],Log[N],f[N][LOG],n;
	inline int cmp(int *a,int x,int y,int l) { return a[x]==a[y]&&a[x+l]==a[y+l]; }
	inline int MyMin(int x,int y) { return h[x+1]<h[y+1]?x:y; }
	inline int getSA(int *a,int n,int m)
	{
		int *x=qwq1,*y=qwq2,i,j,p;
		memset(qwq1,0,sizeof(int)*(2*n+1));
		memset(qwq2,0,sizeof(int)*(2*n+1));
		for(i=1;i<=m;i++) cnt[i]=0;
		for(i=1;i<=n;i++) cnt[x[i]=a[i]]++;
		for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
		for(i=n;i>=1;i--) sa[cnt[x[i]]--]=i;
		for(p=0,j=1;p<=n;j<<=1,m=p)
		{
			for(p=0,i=n-j+1;i<=n;i++) y[++p]=i;
			for(i=1;i<=n;i++) sa[i]>j?y[++p]=sa[i]-j:0;
			for(i=1;i<=m;i++) cnt[i]=0;
			for(i=1;i<=n;i++) cnt[v[i]=x[y[i]]]++;
			for(i=1;i<=m;i++) cnt[i]+=cnt[i-1];
			for(i=n;i>=1;i--) sa[cnt[v[i]]--]=y[i];
			for(swap(x,y),p=i=1;i<=n;i++)
				x[sa[i]]=(cmp(y,sa[i],sa[i-1],j)?p-1:p++);
		}
	//	for(i=1;i<=n;i++) debug(i)sp,debug(sa[i])ln;
		for(i=1;i<=n;i++) rk[sa[i]]=i;
		for(i=1,p=0;i<=n;h[rk[i++]]=p)
			for((p?p--:0),j=sa[rk[i]-1];a[i+p]==a[j+p];p++);
		rep(i,1,n-1) f[i][0]=i;
		for(j=1;(1<<j)<n;j++)
			for(i=1;i+(1<<j)-1<n;i++)
				f[i][j]=MyMin(f[i][j-1],f[i+(1<<(j-1))][j-1]);
		for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
		return 0;
	}
	inline int query(int l,int r)
	{
		int k=Log[r-l+1];
		return MyMin(f[l][k],f[r-(1<<k)+1][k]);
	}
	db solve(int l,int r)
	{
		if(l==r) return n-sa[l]+1;
		int p=query(l,r-1),v=h[p+1];
		db vl=solve(l,p),vr=solve(p+1,r);
		db x=(vr-v)/(vl+vr-2*v),y=1-x;
		return x*x*vl+y*y*vr+2*x*y*v;
	}
	inline db getans(char *s,int _n)
	{
		n=_n;rep(i,1,n) a[i]=s[i]-'a'+1;
		return getSA(a,n,30),solve(1,n);
	}
}using SA::getans;
char s[N];
int main()
{
	return scanf("%s",s+1),!printf("%.6lf\n",double(getans(s,(int)strlen(s+1))));
}

你可能感兴趣的:(后缀数组,学习笔记,纳什均衡)