【BJOI2019】奥术神杖

题面

https://www.luogu.org/problem/P5319

追不到北京的小姐姐,只能写北京的省选了。。。。

题解

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<cmath>
#include<vector>
#define N 2000
#define M 2000
#define eps 1e-7
#define INF 1000000007.0
#define ri register int
using namespace std;

struct node{
  int pre,trans;
} g[N][M];

char s[N];
char t[N];
int n,m;

struct AC{
  int nex[N],ch[N][10];
  int cnt[N];
  double v[N],nv[N];
  double f[N][M];
  vector<int> son[N];
  int tot;
  void insert(double x) {
    int now=0;
    for (ri i=1,l=strlen(s+1);i<=l;i++) {
      int c=s[i]-'0';
      if (!ch[now][c]) ch[now][c]=++tot;
      now=ch[now][c];
    }
    cnt[now]++;
    v[now]=x;
  }
  void getfail() {
    queue<int> q;
    for (ri i=0;i<=9;i++) if (ch[0][i]) q.push(ch[0][i]);
    while (!q.empty()) {
      int x=q.front(); q.pop();
      for (ri i=0;i<=9;i++) {
        int y=ch[x][i];
        if (!y) ch[x][i]=ch[nex[x]][i]; else nex[y]=ch[nex[x]][i],q.push(y);
      }
    }
  }
  void dfs(int x){
    nv[x]+=nv[nex[x]];
    for (ri i=0;i<son[x].size();i++) {
      dfs(son[x][i]);
    }
  }
  void init() {
    for (ri i=1;i<=tot;i++) son[nex[i]].push_back(i);
  }
  bool check(double mid) {
    double dv=log(mid)/log(1.0001);
    for (ri i=0;i<=tot;i++) nv[i]=v[i]-dv*cnt[i];
    dfs(0);
    for (ri i=0;i<=n;i++)
      for (ri j=0;j<=tot;j++) f[i][j]=-INF;
    f[0][0]=0;
    for (ri i=0;i<=n-1;i++) if (t[i+1]=='.') {
      for (ri j=0;j<=tot;j++) 
        for (ri c=0;c<=9;c++) if (f[i][j]+nv[ch[j][c]]>f[i+1][ch[j][c]]) {
          g[i+1][ch[j][c]]=(node){j,c};
          f[i+1][ch[j][c]]=f[i][j]+nv[ch[j][c]];
        }
    }
    else {
      for (ri j=0;j<=tot;j++) 
        for (ri c=t[i+1]-'0';c<=t[i+1]-'0';c++) if (f[i][j]+nv[ch[j][c]]>f[i+1][ch[j][c]]) {
          g[i+1][ch[j][c]]=(node){j,c};
          f[i+1][ch[j][c]]=f[i][j]+nv[ch[j][c]];
        }
    }
    for (ri i=0;i<=tot;i++) if (f[n][i]>0) return 1;
    return 0;
  }
  void print() {
    int p=0;
    for (ri i=0;i<=tot;i++) if (f[n][i]>f[n][p]) p=i;
    int ss[N];
    for (ri i=n;i>=1;i--) {
      ss[i]=g[i][p].trans;
      p=g[i][p].pre;
    }
    for (ri i=1;i<=n;i++) cout<<ss[i];
  }
} trie;

int main(){
  scanf("%d %d",&n,&m);
  scanf("%s",t+1);
  double x;
  for(ri i=1;i<=m;i++) {
    scanf("%s %lf",s+1,&x);
    trie.insert(log(x)/log(1.0001));
  }
  trie.getfail();
  trie.init();
  double lb=1.0,rb=1e9;
  for (ri i=1;i<=45;i++) {
    double mid=(lb+rb)/2.0;
    if (trie.check(mid)) lb=mid; else rb=mid;
  }
  //cout<<lb<<endl;
  trie.print();
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/shxnb666/p/11279451.html