[BJOI2019]奥术神杖

Problem

传送门

Solution

根据题意,需要知道神杖所包含了哪些咒语,大可使用自动ac自动机。

关键是如何处理\(\sqrt[c]{Magic}\)这其实也很套路,一眼看过去,觉得根号这个东西显然就不可做,于是想办法消去根号。于是对于这个式子取对数,\(\sqrt[c]{Magic}=\frac{Magic}{c}[Magic = V_1 + V_2 + ... + V_n]\)

对于\(\frac{Magic}{c}\)这种形式的答案,很显然可以01分数规划来解决(其实就是二分答案),然后在ac自动机上去dp,check当前二分的值是否可行即可。

Code

代码常数较大(luogu上O2可过),大可适当调整\(eps\)

#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 3000 + 5;
const int MAX_M = 3000 + 5;
const int MaxChar = 10;
const double inf = 0x3f3f3f3f;
const double eps = 1e-4;
int n,m;
char a[MAX_M];
struct AhoCorasickAutoMaton{
	int sz[MAX_M],root,tot,nxt[MAX_M][MaxChar],fail[MAX_M];
	double val[MAX_M],num[MAX_M];
	AhoCorasickAutoMaton(){tot=root=1;}
	inline void insert(char *s,int Val){
        int p=1;
        int len=strlen(s+1);
        for(int i=1;i<=len;++i){
	        int c=s[i]-'0';
	        if(!nxt[p][c]) nxt[p][c]=++tot;
	        p=nxt[p][c];
        }
        val[p]=log(Val);
        num[p]++;
    }
    inline void build(){
        queue<int> q;
        fail[root]=root;
        for(int i=0;i<MaxChar;++i){
            int v=nxt[root][i];
            fail[v]=root;
            if(v) q.push(v);
            else nxt[root][i]=root;
        }
        while(q.size()){
            int u=q.front();q.pop();
            for(int i=0;i<MaxChar;++i){
                if(nxt[u][i]){
                    int v=nxt[u][i];
                    if(u==root) fail[v]=root;
                    else fail[v]=nxt[fail[u]][i];
                    q.push(v);
                    val[v]+=val[fail[v]];
					num[v]+=num[fail[v]]; 
                }
                else nxt[u][i]=nxt[fail[u]][i];
            }
        }
    }
    double f[MAX_N][MAX_N],w[MAX_M];
    bool vis[MAX_N][MAX_N];
    int pos[MAX_N][MAX_N];
	double dfs(int p,int x){
    	if(vis[p][x])return f[p][x];
	    if(x==n+1){vis[p][x]=1;f[p][x]=w[p];return f[p][x];}
	    if(a[x]=='.'){
	        f[p][x]=-inf;
	        for(int i=0;i<10;i++){
	            double tmp=dfs(nxt[p][i],x+1);
	            if(tmp>f[p][x]){
					f[p][x]=tmp,pos[p][x]=i;
				}
			}
	    }
	    else f[p][x]=dfs(nxt[p][a[x]-'0'],x+1),pos[p][x]=a[x]-'0';
	    vis[p][x]=1;f[p][x]+=w[p];
	    return f[p][x];
	}
    inline bool check(double mid){
    	memset(vis,0,sizeof(vis));
		for(int i=1;i<=tot;++i) w[i]=val[i]-(double)num[i]*mid;
    	return dfs(1,1)>0;
    }
    inline void print(){
    	int p=1;
    	for(int i=1;i<=n;++i){
    		printf("%d",pos[p][i]);
			p=nxt[p][pos[p][i]];
    	}
    }
    inline void calc(){
    	double l=0,r=20;
    	while(l+eps<r){
    		double mid=(l+r)/2;
    		if(check(mid)) l=mid;
    		else r=mid;
    	}
    	memset(vis,0,sizeof(vis));
    	for(int i=1;i<=tot;++i) w[i]=val[i]-(double)num[i]*l;
    	dfs(1,1);
    	print();
    }
}acam;
char s[MAX_M];
int main(){
	scanf("%d%d",&n,&m);
	scanf("%s",a+1);
	for(int i=1;i<=m;++i){
		scanf("%s",s+1);
		int val;
		scanf("%d",&val);
		acam.insert(s,val);
	}
	acam.build();
	acam.calc();
	return 0;
}
posted @ 2022-03-17 15:51  Thermalrays  阅读(48)  评论(0编辑  收藏  举报