日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P3706-[SDOI2017]硬币游戏【高斯消元,字符串hash】

發布時間:2023/12/3 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P3706-[SDOI2017]硬币游戏【高斯消元,字符串hash】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/P3706


題目大意

給出 nnn 個長度為 mmmH/TH/TH/T 串。

開始一個空序列,每次隨機在后面加一個 H/TH/TH/T ,求每個串第一次出現的概率。

1≤n,m≤3001\leq n,m\leq 3001n,m300


解題思路

數據范圍顯然不能在AC自動機上高斯消元,所以得考慮別的方法。

考慮一個很妙的做法,設一個狀態NNN表示目前還沒有匹配完成的串,然后考慮串A=HHTA=HHTA=HHT和串B=THHB=THHB=THH,那么在NNN后面直接插入一個AAA的概率就是p(N+A)=p(N)×2?mp(N+A)=p(N)\times 2^{-m}p(N+A)=p(N)×2?m

但是考慮到有可能NNN先拼出了BBB然后再拼出AAA,此時考慮BBB的后綴對應AAA前綴的有H,HHH,HHH,HH。那么就有
p(N)×2?m=p(N+A)=p(A)+p(B)×2?2+p(B)×2?1p(N)\times 2^{-m}=p(N+A)=p(A)+p(B)\times 2^{-2}+p(B)\times 2^{-1}p(N)×2?m=p(N+A)=p(A)+p(B)×2?2+p(B)×2?1

這樣不難發現對于別的串如果它的一些后綴是這個串的前綴那么就會產生一些概率,用字符串hashhashhash匹配即可。

然后會發現還是少了一個方程,最后一個就是所有串的概率和為111就好了。

這樣就有n+1n+1n+1個方程了。

時間復雜度:O(n2m+n3)O(n^2m+n^3)O(n2m+n3)


code

#include<cstdio> #include<cstring> #include<algorithm> #define ull unsigned long long using namespace std; const int N=310; const ull g=131; int n,m; double a[N][N],b[N],pw[N]; ull h[N][N],p[N];char s[N]; ull geth(int x,int l,int r) {return h[x][r]-h[x][l-1]*p[r-l+1];} void Gauss(int n){for(int i=1;i<=n;i++){int z=i;for(int j=i+1;j<=n;j++)if(a[j][i]>a[z][i])z=i;swap(a[i],a[z]);double x=a[i][i];b[i]/=x;for(int j=i;j<=n;j++)a[i][j]/=x;for(int j=i+1;j<=n;j++){double rate=-a[j][i];for(int k=i;k<=n;k++)a[j][k]+=rate*a[i][k];b[j]+=rate*b[i];}}for(int i=n;i>=1;i--){for(int j=1;j<i;j++){b[j]-=a[j][i]*b[i];a[j][i]=0;}}return; } int main() {scanf("%d%d",&n,&m);p[0]=1;pw[0]=1;for(int i=1;i<=m;i++)pw[i]=pw[i-1]*0.5,p[i]=p[i-1]*g;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]*g+s[j];}for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)for(int k=1;k<=m;k++)if(geth(i,1,k)==geth(j,m-k+1,m))a[i][j]+=pw[m-k];for(int i=1;i<=n;i++)a[i][n+1]=-pw[m],a[n+1][i]=1;b[n+1]=1;Gauss(n+1);for(int i=1;i<=n;i++)printf("%.12lf\n",b[i]);return 0; }

總結

以上是生活随笔為你收集整理的P3706-[SDOI2017]硬币游戏【高斯消元,字符串hash】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。