字符串选做

字符串选做

还是觉得平常考试写代码时候尽量把常数优化一下,毕竟我被卡了好几次了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][j1]×val

好我是神笔

好,我没有发现这个竟然有后效性,而且直接转移显然不可行,而且这样求出来的概率只是每个长度的概率,那么若果还要算的话,其实是所有的期望相比,概率不等于胜利

这个东西显然需要不能直接转移,我转移的这个或许叫每种情况的概率,而且这个东西不能直接相加作为一个人的获胜概率和

那么考虑高斯消元,我们只需要求出每个点被经过的概率就好了

dp[now]=dp[y]×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)); } }

 


__EOF__

本文作者Eternal_Battle
本文链接https://www.cnblogs.com/Eternal-Battle/p/16023772.html
关于博主:这个世界除了你,都知道我喜欢你
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Gnomeshgh_k  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示