其他分享
首页 > 其他分享> > 字符串选做

字符串选做

作者:互联网

字符串选做

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