【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; }