• [LOJ2538][PKUWC2018]Slay the Spire:DP


    分析

    学会新姿势!我们可以通过调整DP顺序来体现选取物品的优先顺序!

    显然选取强化牌的最优策略是倍数从高到低,能选就选,最多选(k-1)张,选取攻击牌的最优策略是伤害从高到低,尽量少选,但最少选(1)张。

    我们可以把强化牌从大到小排序,把攻击牌从小到大排序,令(f[i][j])表示考虑了最大的(i)张强化牌,其中所有可选的强化牌有(j)张的情况的最优策略下的强化倍数和,(g[i])表示考虑了最小的(i)张攻击牌,其中所有可选的攻击牌有(j)张的情况的最优策略下的伤害和。

    状态转移方程如下:

    [f[i][j]=f[i-1][j]+f[i-1][j-1] imes a[i] (j leq k-1) ]

    [f[i][j]=f[i-1][j]+f[i-1][j-1] (j > k-1) ]

    [g[i][j]=b[i] imes inom{i-1}{j-1} (m-j geq k-1) ]

    [g[i][j]=b[i] imes inom{i-1}{j-1}+g[i-1][j-1] (m-j < k-1) ]

    代码

    #include <bits/stdc++.h>
    
    #define rin(i,a,b) for(int i=(a);i<=(b);++i)
    #define irin(i,a,b) for(int i=(a);i>=(b);--i)
    #define trav(i,a) for(int i=head[a];i;i=e[i].nxt)
    #define Size(a) (int)a.size()
    #define pb push_back
    #define mkpr std::make_pair
    #define fi first
    #define se second
    #define lowbit(a) ((a)&(-(a)))
    typedef long long LL;
    
    using std::cerr;
    using std::endl;
    
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    const int MAXN=3005;
    const int MOD=998244353;
    
    int n,m,k,a[MAXN],b[MAXN],f[MAXN],g[MAXN];
    int fac[MAXN],invf[MAXN];
    
    inline int qpow(int x,int y){
    	int ret=1,tt=x%MOD;
    	while(y){
    		if(y&1)ret=1ll*ret*tt%MOD;
    		tt=1ll*tt*tt%MOD;
    		y>>=1;
    	}
    	return ret;
    }
    
    inline int binom(int n,int m){
    	if(n<0||m<0||n<m)return 0;
    	return 1ll*fac[n]*invf[n-m]%MOD*invf[m]%MOD;
    }
    
    void init(){
    	fac[0]=1;rin(i,1,n)fac[i]=1ll*fac[i-1]*i%MOD;
    	invf[n]=qpow(fac[n],MOD-2);irin(i,n-1,0)invf[i]=1ll*invf[i+1]*(i+1)%MOD;
    }
    
    int main(){
    	n=3000;init();
    	int T=read();
    	while(T--){
    		n=read(),m=read(),k=read();
    		rin(i,1,n)a[i]=read();
    		rin(i,1,n)b[i]=read();
    		std::sort(a+1,a+n+1);
    		std::sort(b+1,b+n+1); 
    		rin(i,0,m)f[i]=g[i]=0;
    		f[0]=1,g[0]=0;
    		irin(i,n,1)irin(j,std::min(n-i+1,m),1){
    			if(j<=k-1)f[j]=(f[j]+1ll*f[j-1]*a[i])%MOD;
    			else f[j]=(f[j]+f[j-1])%MOD;
    		}
    		rin(i,1,n)irin(j,std::min(i,m),1){
    			if(m-j<k-1)g[j]=(g[j]+1ll*binom(i-1,j-1)*b[i]+g[j-1])%MOD;
    			else g[j]=(g[j]+1ll*binom(i-1,j-1)*b[i])%MOD;
    		}
    		int ans=0;
    		rin(i,0,m)ans=(ans+1ll*f[i]*g[m-i])%MOD;
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    数论12——浅谈指数与对数
    数论11——大组合数
  • 原文地址:https://www.cnblogs.com/ErkkiErkko/p/10836787.html
Copyright © 2020-2023  润新知