您的位置:首页 > 其它

UVALive 6495 Probability Paradox AC自动机+高斯消元

2014-07-26 22:19 375 查看
题目大意:两个人又两个等长但不同的字符串,现在在一张纸上随机的写字母T和字母H,指导纸上写的字符串包含了某个人的串,如果包含了第一个人的串,那么第一个就获胜,如果是第二个人的串,则第二个人获胜。

好久没做AC自动机了,感觉都生疏了。这题其实不是很难的,关键是第一眼可能被分式吓到了。我们不妨用两人的串构造AC自动机,然后用dp[i]表示当前状态为AC自动机上的i,第一个人获胜的概率。

如样例1“TT HH”构造的AC自动机可以是下图,节点上的数字表示节点标号,我们就用这个标号表示AC自动机上的状态。



我们很容易得到dp方程

dp[0] = 0.5*dp[1] + 0.5*dp[3]
dp[1] = 0.5*dp[2] + 0.5*dp[3]
dp[2] = 1
dp[3] = 0.5*dp[1] + 0.5*dp[4]
dp[4] = 0

我们可以解得dp[0] = 0.5。

其实这个还有个需要注意的细节问题:是否有非标记节点(即根到这个点的路径,表示的是最开始的那两个串)能通过fail指针到达模式串?但是由于两串相同长度,不会有这种情况。

因为直接转移似乎很麻烦,我们采用gauss消元,而这个因为是分式,则计算的时候不是用double,而是用两个long long(结构体)表示一个分数。

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
typedef long long LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const LL INF=1LL<<60;
const double INFF=1e100;
const double eps=1e-8;
const int mod=1000000007;
const int NN=100005;
const int MM=1000010;
/* ****************** */

char ss[15];
const int k_size=2;
const int LEN=12;
struct Tire_Tree
{
int fail;
int p;//0,1,-1
int next[k_size];
void init()
{
p=-1;
fail=-1;
memset(next,-1,sizeof(next));
}
}tire[2*LEN];
int tire_cnt;
int tire_q[2*LEN];
int dui[2*LEN];

LL gcd(LL a,LL b)
{
if(b==0)return a;
return gcd(b,a%b);
}
struct Fraction
{
LL a,b;

Fraction(LL x=1,LL y=1):a(x),b(y){};
Fraction(const Fraction &tt):a(tt.a),b(tt.b){};

void init()
{
LL g=gcd(a,b);
a/=g;
b/=g;
if(a==0)b=1;
}

double val()
{
return (a+0.0)/b;
}

bool operator<(const Fraction &tt)const
{
return a*tt.b < tt.a*b;
}
bool operator>(const Fraction &tt)const
{
return a*tt.b > tt.a*b;
}
bool operator==(const Fraction &tt)const
{
return a*tt.b == tt.a*b;
}
bool operator!=(const Fraction &tt)const
{
return (a*tt.b) != (tt.a*b);
}
bool operator<=(const Fraction &tt)const
{
return a*tt.b <= tt.a*b;
}
bool operator>=(const Fraction &tt)const
{
return a*tt.b >= tt.a*b;
}

Fraction operator+(const Fraction &tt)const
{
Fraction temp;
temp.a = a*tt.b + tt.a*b;
temp.b = b*tt.b;
temp.init();
return temp;
}
Fraction operator-(const Fraction &tt)const
{
Fraction temp;
temp.a = a*tt.b - tt.a*b;
temp.b = b*tt.b;
temp.init();
return temp;
}
Fraction operator*(const Fraction &tt)const
{
Fraction temp;
temp.a = a*tt.a;
temp.b = b*tt.b;
temp.init();
return temp;
}
//如果是除以0,这这个分式变为 ?/0
Fraction operator/(const Fraction &tt)const
{
Fraction temp;
temp.a = a*tt.b;
temp.b = b*tt.a;
temp.init();
return temp;
}
};

void tire_insert(char *str,int le,int root)
{
int i,x,p=root;
for(i=0;str[i];i++)
{
if(str[i]=='T')
x=0;
else
x=1;
if(tire[p].next[x]==-1)
{
tire_cnt++;
tire[tire_cnt].init();
tire[p].next[x]=tire_cnt;
}
p=tire[p].next[x];
}
tire[p].p=le;
}
void init_fail(int root)
{
int head,tail,i,fa,p=root;

head=1;
tail=0;
tire[root].fail=root;
for(i=0;i<k_size;i++)
{
if(tire[p].next[i]!=-1)
{
tire_q[++tail]=tire[p].next[i];
tire[ tire_q[tail] ].fail=root;
}
else
tire[p].next[i]=root;
}

while(head<=tail)
{
p=tire_q[head++];
fa=tire[p].fail;

for(i=0;i<k_size;i++)
{
if(tire[p].next[i]!=-1)
{
tire_q[++tail]=tire[p].next[i];
tire[ tire_q[tail] ].fail=tire[fa].next[i];
}
else
tire[p].next[i]=tire[fa].next[i];
}
}
}

Fraction gss[2*LEN][2*LEN+1];
Fraction gss_ans[2*LEN];
//行列编号都从0开始,包含系数列,矩阵大小为n*m
//此函数保证只有1个解才能用
void gauss(int n,int m)
{
int i,j,k,pca;
Fraction temp,temp1;
for(i=0;i<n;i++)
{
pca=i;
for(j=i+1;j<n;j++)
{
if( fabs( gss[j][i].val() ) > fabs( gss[pca][i].val() ))
pca=j;
}
if(pca!=i)
{
for(j=i;j<m;j++)
{
swap(gss[i][j],gss[pca][j]);
}
}
//如果此位已经是0,则答案是无限个解或无解?应该是吧
if( gss[i][i] != Fraction(0,1) )
{
for(j=i+1;j<n;j++)
{
temp = gss[j][i]/gss[i][i];
gss[j][i] = Fraction(0,1);
for(k=i+1;k<m;k++)
{
temp1 = gss[i][k]*temp;
gss[j][k] = gss[j][k] - temp1;
}
}
}
}
//因为是唯一解,所以这么写
for(i=m-2;i>=0;i--)
{
gss_ans[i]=gss[i][m-1];
for(j=i+1;j<m-1;j++)
{
temp = gss_ans[j]*gss[i][j];
gss_ans[i] = gss_ans[i] - temp;
}
gss_ans[i] = gss_ans[i]/gss[i][i];
}
}

int main()
{
int i,j,tire_root;
int n,m,tol;
int y,z;
while(1)
{
scanf("%s",ss);
if(strcmp(ss,"$")==0)break;

tire_root=tire_cnt=0;
tire[0].init();
tire_insert(ss,1,tire_root);
scanf("%s",ss);
tire_insert(ss,0,tire_root);
init_fail(tire_root);

n=tire_cnt+1;
m=tire_cnt;
tol=0;
for(i=0;i<=tire_cnt;i++)
{
if(tire[i].p==-1)
{
dui[i]=tol++;
}
}
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
gss[i][j] = Fraction(0,1);
}
for(i=0;i<=tire_cnt;i++)
{
if(tire[i].p!=-1)continue;

y=tire[i].next[0];
z=tire[i].next[1];

gss[i][ dui[i] ] = gss[i][ dui[i] ]+Fraction(1,1);

if(tire[y].p==-1)
{
gss[i][ dui[y] ] = gss[i][ dui[y] ]+Fraction(-1,2);
}
else if(tire[y].p==1)
{
gss[i][m-1] = gss[i][m-1] + Fraction(1,2);
}

if(tire[z].p==-1)
{
gss[i][ dui[z] ] = gss[i][ dui[z] ]+Fraction(-1,2);
}
else if(tire[z].p==1)
{
gss[i][m-1] = gss[i][m-1] + Fraction(1,2);
}
}

gauss(n,m);

printf("%lld/%lld\n",gss_ans[dui[0]].a,gss_ans[dui[0]].b);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: