zoukankan      html  css  js  c++  java
  • [BJOI 2019] 奥术神杖

    ( ext{Description})

    传送门

    ( ext{Solution})

    发现有 (ans=sqrt[c]{prod_{i=1}^c v_i})。不过显然这个东西直接算出来会爆。

    有一个操作就是同时取对数。就有:

    [ln ans=lnleft(sqrt[c]{prod_{i=1}^c v_i} ight ) ]

    [ln ans=frac{1}{c} lnleft(prod_{i=1}^c v_i ight ) ]

    [ln ans=frac{1}{c} sum_{i=1}^c ln v_i ]

    因为 (e>1)(ln(x)) 是单增的,所以就是求 (frac{1}{c} sum_{i=1}^c ln v_i) 的最大值。观察柿子,有一个未知的求和柿子和与之相配的系数。想到了什么?(0/1) 分数规划!

    所以二分答案 (mid),若有:

    [mid<frac{1}{c} sum_{i=1}^c ln v_i ]

    [ccdot mid<sum_{i=1}^c ln v_i ]

    [sum_{i=1}^c left(ln v_i-mid ight)>0 ]

    我们可以对于每个 (mid),求出 (sum_{i=1}^c left(ln v_i-mid ight)) 的最大值(这里的所有 (v) 显然是自己选定)。如果满足最大值 (>0),说明 (mid) 还可以取到更大(带回原来的柿子看)。

    对于求出 (sum_{i=1}^c left(ln v_i-mid ight)) 的最大值,显然就是将单个咒语权值减 (mid),用 ( ext{AC}) 自动姬统计某个后缀出现的权值(这个后缀可能包含很多咒语),然后大力 ( ext{DP})

    (f[i][j]) 为到神杖的第 (i) 位,在 ( ext{AC}) 自动姬上的节点 (j) 的最大值。(如果不是很懂为什么要取节点 (0),可以看看我的这篇博客

    就有:

    [f_{i+1,son_{j,k}}=max{f_{i,j}+val_{son_{j,k}},f_{i+1,son_{j,k}}} ]

    (son_{j,k}) 就是本轮添加字符 (k) 对应的节点。

    ( ext{Code})

    #include <cstdio>
    
    #define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
    #define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
    #define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define print(x,y) write(x),putchar(y)
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
    template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
    template <class T> inline T fab(const T x) {return x>0?x:-x;}
    template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
    template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
    template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
    
    #include <cmath>
    #include <queue>
    #include <cstring>
    using namespace std;
    
    const int maxn=1505;
    const double eps=1e-6,inf=1e11;
    
    int n,m,Value,t[maxn][12],tot,num[maxn],f[maxn],memo[maxn][maxn][2];
    char s[maxn],ori[maxn],ans[maxn];
    double val[maxn],dp[maxn][maxn];
    queue <int> q;
    
    void Insert() {
    	int p=0,len=strlen(s+1);
    	rep(i,1,len) {
    		int d=s[i]-'0';
    		if(!t[p][d]) t[p][d]=++tot;
    		p=t[p][d]; 
    	}
    	++num[p],val[p]+=log2(Value);
    }
    
    void GetFail() {
    	rep(i,0,9) if(t[0][i]) q.push(t[0][i]);
    	while(!q.empty()) {
    		int u=q.front(); q.pop();
    		val[u]+=val[f[u]],num[u]+=num[f[u]];
    		rep(i,0,9)
    			if(t[u][i]) f[t[u][i]]=t[f[u]][i],q.push(t[u][i]);
    			else t[u][i]=t[f[u]][i];
    	}
    }
    
    bool ok(double x) {
    	rep(i,0,tot) val[i]-=x*num[i];
    	rep(i,0,n) rep(j,0,tot) dp[i][j]=-inf;
    	dp[0][0]=0;
    	rep(i,0,n-1) rep(j,0,tot) rep(k,0,9)
    		if(ori[i+1]=='.'||ori[i+1]==k+'0') {
    			if(dp[i+1][t[j][k]]<dp[i][j]+val[t[j][k]]) {
    				dp[i+1][t[j][k]]=dp[i][j]+val[t[j][k]];
    				memo[i+1][t[j][k]][0]=j,memo[i+1][t[j][k]][1]=k;
    			}
    		}
    	rep(i,0,tot) val[i]+=x*num[i];
    	int pos=0;
    	rep(i,1,tot) if(dp[n][i]>dp[n][pos]) pos=i; // 找匹配 n 位后值最大
    	if(dp[n][pos]>0) {
    		for(int i=n,now=pos;i>=1;now=memo[i][now][0],--i) ans[i]=memo[i][now][1]+'0';
    		return 1;
    	}
    	return 0;
    } 
    
    int main() {
    	n=read(9),m=read(9),scanf("%s",ori+1);
    	rep(i,1,m) scanf("%s",s+1),Value=read(9),Insert();
    	GetFail();
    	double l=0,r=log2(1e9+7),mid; // 因为 V_i<=1e9,所以其集合平均数也在这个范围
    	while(r-l>eps) {
    		mid=(l+r)/2;
    		if(ok(mid)) l=mid;
    		else r=mid;
    	}
    	ok(l); puts(ans+1);
    	return 0;
    }
    
  • 相关阅读:
    swift 自学小计
    修改非空表字段类型Oracle
    DBNull.value
    修改SqlServer字段长度
    未在本地计算机上注册“Microsoft.Ace.OleDB.12.0”
    引用dll文件要复制到本地
    oracle与SqlServer连接串服务器地址
    生成几乎永不重复的串
    安装SqlServer2008后vs中dev控件消失
    Ios项目添加Pods
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14182001.html
Copyright © 2011-2022 走看看