• [Luogu5319][BJOI2019]奥术神杖(分数规划+AC自动机)


    对最终答案取对数,得到$ln(Ans)=frac{1}{c}sum ln(v_i)$,典型的分数规划问题。
    二分答案后,对所有咒语串建立AC自动机,然后套路地$f[i][j]$表示走到T的第i个字符,当前在自动机的第j个位置,能得到的最大收益。
    注意二分的r初始不能设太大,25就可以了,二分终止的eps最好设到1e-5,否则会WA或者TLE。

     1 #include<cmath>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     6 using namespace std;
     7 
     8 const int N=2010,inf=1e9;
     9 const double eps=1e-5;
    10 char S[N],ss[N][N],pre[N][N];
    11 int n,m,x,nd,sz[N],fail[N],q[N],son[N][11],fr[N][N];
    12 double v[N],w[N],f[N][N];
    13 
    14 void add(char s[],double v){
    15     int x=0,len=strlen(s+1);
    16     rep(i,1,len){
    17         int c=s[i]-'0';
    18         if (!son[x][c]) son[x][c]=++nd;
    19         x=son[x][c];
    20     }
    21     w[x]+=v; sz[x]++;
    22 }
    23 
    24 void bfs(){
    25     int st=0,ed=0;
    26     rep(i,0,9) if (son[0][i]) q[++ed]=son[0][i];
    27     while (st!=ed){
    28         int x=q[++st];
    29         rep(i,0,9) if (son[x][i]) fail[son[x][i]]=son[fail[x]][i],q[++ed]=son[x][i];
    30             else son[x][i]=son[fail[x]][i];
    31         w[x]+=w[fail[x]]; sz[x]+=sz[fail[x]];
    32     }
    33 }
    34 
    35 double solve(double mid){
    36     rep(i,0,n) rep(j,0,nd) f[i][j]=-inf;
    37     f[0][0]=0; double ans=-inf;
    38     rep(i,0,n-1) rep(j,0,nd){
    39         if (S[i+1]!='.'){
    40             int t=son[j][S[i+1]-'0'];
    41             if (f[i][j]+w[t]-mid*sz[t]>f[i+1][t])
    42                 f[i+1][t]=f[i][j]+w[t]-mid*sz[t],fr[i+1][t]=j;
    43             continue;
    44         }
    45         rep(c,0,9){
    46             int t=son[j][c];
    47             if (f[i][j]+w[t]-mid*sz[t]>f[i+1][t])
    48                 f[i+1][t]=f[i][j]+w[t]-mid*sz[t],fr[i+1][t]=j,pre[i+1][t]=c+'0';
    49         }
    50     }
    51     rep(i,0,nd) ans=max(ans,f[n][i]); return ans;
    52 }
    53 
    54 void Print(int i,int j){
    55     if (!i) return;
    56     Print(i-1,fr[i][j]);
    57     if (S[i]!='.') putchar(S[i]); else putchar(pre[i][j]);
    58 }
    59 
    60 int main(){
    61     freopen("arcana.in","r",stdin);
    62     freopen("arcana.out","w",stdout);
    63     scanf("%d%d%s",&n,&m,S+1);
    64     rep(i,1,m) scanf("%s%d",ss[i]+1,&x),v[i]=log(x),add(ss[i],v[i]);
    65     double L=0,R=25; bfs();
    66     while (L+eps<R){
    67         double mid=(L+R)/2;
    68         if (solve(mid)>0) L=mid; else R=mid;
    69     }
    70     solve(L); int mn=-inf,mnd=0;
    71     rep(i,0,nd) if (f[n][i]>mn) mn=f[n][i],mnd=i;
    72     Print(n,mnd);
    73     return 0;
    74 }
  • 相关阅读:
    用Fusion Log诊断同一版本冲突问题解决
    SQLSERVER 切换数据库为单用户和多用户模式
    redis常用命令
    linq函数All,Any,Aggregate说明
    rabbitmq部署安装
    Centos7防火墙常用命令
    SQL SERVER添加表注释、字段注释
    Windows定时任务管理以及服务管理
    SQLServer 2008数据库查看死锁、堵塞的SQL语句
    SQLServer查询死锁
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10799312.html
Copyright © 2020-2023  润新知