字符串选做
作者:互联网
字符串选做
还是觉得平常考试写代码时候尽量把常数优化一下,毕竟我被卡了好几次了$QAQ$
时间不太够,为了扩充题量,就用云题补充一下
$BJOI2017$魔法咒语
我一开始会考虑到$dp[now][i][j]$表示目前转移到$now$节点,目前转移到第$i$个字符串的第$j$个位置的方案数
显然你转移到不合法节点直接一直赋值$0$就好了
这样复杂度还是很危
显然这个状态无法满足转移先后,那么可以很自然的想到,我们跑转移的时候长度是递增的,我们当前状态必然是从原来的长度短的状态转移过来,那么状态易得
发现其实第二三维并不是很重要,因为我们发现转移的时候直接一个串顺着转移了,就可以很容易到了目标节点,但是为了不转移混乱第二维度就记录长度就很好说了
$dp[y][i+len[j]]+=dp[now][i]$目前从$now$转移字符串$j$,中间出现不合法的直接不转移就好了
显然这个东西不能拿全部的分,最后又有两个特殊性质,而且长度直接变为$1e8$
那么线性都过不去的话,对于这种的话,显然套一个矩阵就好了,我感觉我超喜欢矩阵优化(或许是考场上直接造出来了)的题...
那么发现这个转移只和前两个位置有关
矩阵大概和斐波那契矩阵一样,维护每个位置两个长度的$dp$值,然后把能转移的节点在转移矩阵上加上贡献就好了
$JSOI2009$有趣的游戏
一眼上去还是一个$AC$自动机上的$DP?$
这个感觉很短吧
$dp[now][j]$表示目前转移到$now$节点长度为$j$的概率总和$?$
$dp[y][j]+=dp[now][j-1]\times val$
好我是神笔
好,我没有发现这个竟然有后效性,而且直接转移显然不可行,而且这样求出来的概率只是每个长度的概率,那么若果还要算的话,其实是所有的期望相比,概率不等于胜利
这个东西显然需要不能直接转移,我转移的这个或许叫每种情况的概率,而且这个东西不能直接相加作为一个人的获胜概率和
那么考虑高斯消元,我们只需要求出每个点被经过的概率就好了
$dp[now]=\sum dp[y]\times lv[y]$
这个东西我竟然没看出来有后效性,我是傻了吧...
#include<bits/stdc++.h> #define MAXN 250 using namespace std; bool tag[MAXN]; double a[MAXN][MAXN],lv[MAXN]; vector<pair<int,double> >rd[MAXN]; int fail[MAXN],Peo[MAXN],tr[MAXN][26],id[MAXN],tot,n,m,l,p,q; char s[MAXN]; void Get_fail() { queue<int>q; int now=0; for(int i=0;i<m;i++) { if(tr[now][i]) { q.push(tr[now][i]); } } while(q.size()) { int now=q.front(); q.pop(); for(int i=0;i<m;i++) { if(tr[now][i]) { fail[tr[now][i]]=tr[fail[now]][i]; q.push(tr[now][i]); } else { tr[now][i]=tr[fail[now]][i]; } } } } void Get_edge() { for(int i=0;i<=tot;i++) { if(tag[i]) continue; for(int j=0;j<m;j++) { int y=tr[i][j]; rd[y].push_back(make_pair(i,lv[j])); } } } void guass() { for(int i=0;i<=tot;i++) { int maxn=i; for(int j=i+1;j<=tot;j++) { if(fabs(a[maxn][i])<fabs(a[j][i])) maxn=j; } swap(a[maxn],a[i]); for(int j=0;j<=tot;j++) { if(i==j) continue; double tmp=a[j][i]/a[i][i]; for(int k=0;k<=tot+1;k++) { a[j][k]-=a[i][k]*tmp; } } } for(int i=0;i<=tot;i++) { a[i][tot+1]/=a[i][i]; } } int main() { scanf("%d%d%d",&n,&l,&m); for(int i=0;i<m;i++) { scanf("%d%d",&p,&q); if(p==0) p=0.001; lv[i]=(p*1.0)/(q*1.0); } for(int i=1,now=0;i<=n;i++) { scanf("%s",s+1); now=0; for(int j=1;s[j];j++) { if(!tr[now][s[j]-'A']) { tr[now][s[j]-'A']=++tot; id[tot]=s[j]-'A'; } now=tr[now][s[j]-'A']; } tag[now]=true; Peo[i]=now; } Get_fail(); Get_edge(); for(int i=0;i<=tot;i++) { if(i==0) a[i][tot+1]=-1; a[i][i]=-1; for(int j=0;j<rd[i].size();j++) { int y=rd[i][j].first; double p=rd[i][j].second; a[i][y]+=p; } } guass(); for(int i=1;i<=n;i++) { a[Peo[i]][tot+1]=max(a[Peo[i]][tot+1],0.00001); printf("%.2f\n",max(a[Peo[i]][tot+1],0.0)); } }
标签:选做,概率,MAXN,字符串,长度,now,转移,dp 来源: https://www.cnblogs.com/Eternal-Battle/p/16023772.html