10个人围在一起丢色子,每个人给一个长度为l的序列,色子可以丢无限次,谁的序列先出现谁就胜利,游戏结束。
先说个暴力Y解,先建立AC自动机,然后很容易想到dp[I][J] 第i步走到状态j的概率,然后很明显次数可以用矩阵优化,然而我的姿势怎么也卡不过去。。。。
正解是喜闻乐见的高斯消元,和 游走 一样,先对每个状态建立方程组,然后把初始状态的概率设为1(初始状态即为失配状态)由于一开始由0出发,(很多次后的概率)应该与从其他状态推过来的和为0 再算上初始的概率)所以增广列的第一个值为1 由于前面0状态的系数为-1 所以值改为-1
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define eps 1e-6
using namespace std;
int T,n,siz,ans;
int a[500][7],q[5001],fail[5001],vis[5001];
int ed[500],len,s[51];
double an[201][201];
double sqr(double x){return x*x;}
void ins(int x)
{
int now=0;
for(int i=1;i<=len;i++)
{
int t=s[i];
if(a[now][t])now=a[now][t];
else now=a[now][t]=++siz;
}
vis[now]++;
ed[x]=now;
}
void acmach(){
int head=0,tail=1,k,now;
q[1]=0;fail[0]=0;
while(head<tail)
{
head++;
now=q[head];
for(int i=1;i<=6;i++)
{
if(!a[now][i])
{
a[now][i]=a[fail[now]][i];
}
else
{
int temp=a[now][i];
if(now) fail[temp]=a[fail[now]][i];
tail++; q[tail]=temp;
}
}
}
}
bool gauss(int x)
{
int now=0,to;double t;
for(int i=0;i<=x;i++)
{
for(to=now;to<=x;to++)if(fabs(an[to][i])>eps)break;
if(to>x)continue;
if(to!=now)for(int j=0;j<=x+1;j++)
swap(an[to][j],an[now][j]);
t=an[now][i];
for(int j=0;j<=x+1;j++)
an[now][j]/=t;
for(int j=0;j<=x;j++)
if(j!=now)
{
t=an[j][i];
for(int k=0;k<=x+1;k++)
an[j][k]-=t*an[now][k];
}
now++;
}
}
void solve()
{
for(int i=0;i<=siz;i++)
{
if(vis[i]) continue;
for(int j=1;j<=6;j++)
{
an[a[i][j]][i]+=1.0/6.0;
}
}
for(int i=0;i<=siz;i++)
{
an[i][i]+=-1.0;
}
an[0][siz+1]=-1.0;
}
void pri()
{
for(int i=0;i<=siz;i++)
{
for(int j=0;j<=siz+1;j++)
{
printf("%.2lf ",an[i][j]);
}
printf("\n");
}
}
void init()
{
memset(a,0,sizeof(a));
memset(an,0.0,sizeof(an));
memset(vis,0,sizeof(vis));
memset(fail,0,sizeof(fail));
}
int main()
{
scanf("%d",&T);
while(T--)
{
init();
siz=0;ans=0;
scanf("%d%d",&n,&len);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=len;j++) scanf("%d",&s[j]);
ins(i);
}
acmach();
solve();
gauss(siz);
double sum=0.0;
for(int i=1;i<=n;i++) sum+=an[ed[i]][siz+1];
for(int i=1;i<n;i++) printf("%.6lf ",an[ed[i]][siz+1]/sum);
printf("%.6lf\n",an[ed[n]][siz+1]/sum);
}
return 0;
}
/*
3
5 1
1
2
3
4
5
6 2
1 1
2 1
3 1
4 1
5 1
6 1
4 3
1 2 3
2 3 4
3 4 5
4 5 6
*/
再附上怎么也过不了的矩阵
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define eps 1e-6
using namespace std;
inline int getint()
{
int res=0,f=1;char c;
while(c=getchar(),c<'0'||c>'9'){if(c=='-')f=-1;}
res=c-'0';
while(c=getchar(),c>='0'&&c<='9')res=res*10+c-'0';
return res*f;
}
int T,n,siz,ans;
int a[110][7],q[111],fail[111],vis[111];
int ed[500],len,s[51];
void ins(int x)
{
int now=0;
for(int i=1;i<=len;i++)
{
int t=s[i];
if(a[now][t])now=a[now][t];
else now=a[now][t]=++siz;
}
vis[now]++;
ed[x]=now;
}
void acmach(){
int head=0,tail=1,k,now;
q[1]=0;fail[0]=0;
while(head<tail)
{
head++;
now=q[head];
for(int i=1;i<=6;i++)
{
if(!a[now][i])
{
a[now][i]=a[fail[now]][i];
}
else
{
int temp=a[now][i];
if(now) fail[temp]=a[fail[now]][i];
tail++; q[tail]=temp;
}
}
}
}
struct matrix
{
double a[101][101];
void init()
{
memset(a,0,sizeof(a));
}
void pri()
{
printf("*****************\n");
for(int i=0;i<=siz*2+1;i++)
{
for(int j=0;j<=siz*2+1;j++)
printf("%lf ",a[i][j]);
printf("\n");
}
}
};
matrix cc1,cc2;
double rt[1000];
matrix tmp1,tmp2;
matrix res;
void mul1()
{
cc1.init();
cc2.init();
for(int i=0;i<=siz;i++)
{
for(int j=0;j<=siz;j++)
{
//cc1.a[i][j]=0;
for(int k=0;k<=siz;k++)
{
cc1.a[i][j]+=tmp1.a[i][k]*tmp1.a[k][j];
}
}
}
for(int i=0;i<=siz;i++)
{
for(int j=0;j<=siz;j++)
{
//cc2.a[i][j]=0;
for(int k=0;k<=siz;k++)
{
cc2.a[i][j]+=tmp1.a[i][k]*tmp2.a[k][j];
}
cc2.a[i][j]+=tmp2.a[i][j];
}
}
tmp2=cc2;tmp1=cc1;
}
void solve()
{
tmp1.init();
for(int i=0;i<=siz;i++)
{
if(vis[i]) continue;
for(int j=1;j<=6;j++)
{
tmp1.a[i][a[i][j]]+=1.0/6.0;
}
}
tmp2=tmp1;
for(int i=1;i<=20;i++)
{
mul1();
}
for(int i=1;i<=n;i++) rt[i]=tmp2.a[0][ed[i]];
double sum=0.0;
for(int i=1;i<=n;i++) sum+=rt[i];
for(int i=1;i<n;i++) printf("%.6lf ",rt[i]/sum);
printf("%.6lf\n",rt[n]/sum);
}
void init()
{
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
memset(fail,0,sizeof(fail));
}
int main()
{
scanf("%d",&T);
while(T--)
{
init();
siz=0;
n=getint();len=getint();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=len;j++) s[j]=getint();
ins(i);
}
acmach();
solve();
}
return 0;
}
/*
3
5 1
1
2
3
4
5
6 2
1 1
2 1
3 1
4 1
5 1
6 1
4 3
1 2 3
2 3 4
3 4 5
4 5 6
*/