首页 > 其他 > 详细

SDOI2017硬币游戏

时间:2020-03-18 13:10:02      阅读:54      评论:0      收藏:0      [点我收藏+]

技术分享图片
\(n,m300\)

很容易想到建出AC自动机后暴力高斯消元的\(O(^3m^3)40\)分做法

SOL:

这题和CSTC2006歌唱王国很像

定义:
\(a_{i,j,k}\)表示\(A_i[1,k]\)是否等于\(A_j[m-k+1,m]\)

\(f_{i,j}\)表示\(A_i\)出现时长度为\(j\)的概率,其生成函数为\(F_i(X)\)

\(g_i\)表示长度为\(i\)的序列未出现任何串的概率,其生成函数为\(G(x)\)

\[G(x)+\sum F_i(x)=1+G(x)*x\]

对于任意一个串\(i\)

\[G(x)*\frac 1{2^m}x^m=\sum_{j=1}^n\sum_{k=1}^ma_{i,j,k}*F_j(x)*\frac 1{2^{m-k}}x^{m-k}\]

\(x=1\)代入二试:

\[G(1)=\sum^n_{j=1}\sum^m_{k=1}a_{i,j,k}*F_j(1)*2^k\]

需解出\(G(1),F_i(1)\),加上\(\sum F_i(1)=1\),一共\(n+1\)个式子,高斯消元即可

时间复杂度\(O(n^3)\)

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f==1?x:-x;
}
#define ll long long
const int N=304,mod=1e9+7;
const double eps=1e-10;
int n,m,h[N][N],b[N];
char s[N];
double a[N][N],db[N];
inline int hsh(int x,int l,int r){
    return (h[x][r]-(ll)h[x][l-1]*b[r-l+1]%mod+mod)%mod;
}
inline void gauss(int n){
    for(int i=1,id;i<=n;i++){
        id=i;
        for(int j=i+1;j<=n;j++)
            if(fabs(a[j][i])>fabs(a[id][i]))id=i;
        if(id!=i)swap(a[id],a[i]);
        for(int j=i+1;j<=n;j++){
            double tmp=a[j][i]/a[i][i];
            for(int k=i;k<=n+1;k++){
                a[j][k]-=a[i][k]*tmp;
            }
        }
    }
    for(int i=n;i;i--){
        for(int j=i+1;j<=n;j++)
            a[i][n+1]-=a[i][j]*a[j][n+1];
        a[i][n+1]/=a[i][i];
    }
}
int main(){
    n=read();m=read();
    b[0]=db[0]=1;
    for(int i=1;i<=m;i++){
        b[i]=(b[i-1]<<1)%mod;
        db[i]=db[i-1]*2;
    }
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        for(int j=1;j<=m;j++)
            h[i][j]=((h[i][j-1]<<1)+(s[j]=='H'))%mod;
    } 
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)
            for(int k=1;k<=m;k++)
                if(hsh(i,1,k)==hsh(j,m-k+1,m))a[i][j]+=db[k];
        a[i][n+1]=-1;
    }
    for(int i=1;i<=n;i++)
        a[n+1][i]=a[n+1][n+2]=1;
    gauss(n+1);
    for(int i=1;i<=n;i++)
        printf("%.8lf\n",a[i][n+2]); 
    return (0-0);
}

SDOI2017硬币游戏

原文:https://www.cnblogs.com/aurora2004/p/12516678.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!