zoukankan      html  css  js  c++  java
  • 「PKUWC2018」Slay the Spire

    loj2538 「PKUWC 2018」Slay the Spire

    对于这种题,感觉可以贪心

    所以要先手玩,看看有没有最优决策

    发现,如果k张,必定先打强化

    关键的话是:“每个强化牌翻的倍数大于1”

    意味着,多翻一倍少打一张攻击一定不劣。

    如果m张,有i张是强化,选k个,

    如果i<k,那么打i张强化,剩下打攻击

    如果i>=k,打k-1张强化,1张攻击

    发现,决策和分到的强化牌的数量有关系

    从这方面dp

    F(i,j)表示,分到i张强化,打出j张,所有的翻的倍率(卡牌乘积)的和

    G(i,j)表示,分到i张攻击,打出j张,所有方案的(原始)伤害的和

    那么答案就是:F(i,i)*G(m-i,k-i)和F(i,k-1)*G(m-i,1)(乘法分配律)

    考虑怎么求F,G

    有了一些牌,一定打最大的一些个

    所以sort

    然后,f[i][j]表示,前i个以i结尾,选择了j个强化牌所翻的倍率的和

    dp,前缀和优化即可。

    g[i][j]表示,前i个以i结尾,选择了j个攻击牌所有方案的伤害的和

    同上处理

    然后枚举强化牌i张,

    F,G只需要计算n次,所以不用预处理。每次暴力求,枚举最后一个选择的是谁,剩下位置组合数来搞。

    注意,f[i][0]是C(n,i),象征选择的方案数,因为乘法的单位元是1,不能没有。

    没有强化牌认为翻1倍。

    而g[i][0]就是0啦。

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define numb (ch^'0')
    #define int long long
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=3003;
    const int mod=998244353;
    int f[N][N],g[N][N],c[N][N];
    int s[N],t[N];
    int a[N],b[N];
    int n,m,k;
    void clear(){
        
    }
    bool cmp(int x,int y){
        return x>y;
    }
    int F(int x,int y){
        if(x<y) return 0;
        //if(x==0&&y==0) return 1;
        if(!y) return c[n][x];
        int ret=0;
        for(reg i=y;i<=n;++i){
            ret=(ret+(ll)f[i][y]*c[n-i][x-y])%mod;
        }
        return ret;
    }
    int G(int x,int y){
        if(x<y) return 0;
        //if(x==0||y==0) return 0;
        int ret=0;
        for(reg i=y;i<=n;++i){
            ret=(ret+(ll)g[i][y]*c[n-i][x-y])%mod;
        }
        return ret;
    }
    int main(){
        int T;
        //while(1);
        rd(T);
        c[0][0]=1;
        for(reg i=1;i<=3000;++i){
            c[i][0]=1;
            for(reg j=1;j<=i;++j){
                c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
            }
        }
        while(T--){
            rd(n);rd(m);rd(k);
            clear();
            for(reg i=1;i<=n;++i) rd(a[i]);
            for(reg j=1;j<=n;++j) rd(b[j]);
            sort(a+1,a+n+1,cmp);sort(b+1,b+n+1,cmp);
            
            memset(s,0,sizeof s);
            memset(t,0,sizeof t);
            t[0]=1;
            s[0]=1;
            for(reg i=1;i<=n;++i){
                for(reg j=i;j>=1;--j){
                    f[i][j]=(ll)a[i]*s[j-1]%mod;    
                }
                for(reg j=i;j>=1;--j){
                    s[j]=(s[j]+f[i][j])%mod;
                }
            }
            memset(s,0,sizeof s);
            memset(t,0,sizeof t);
            t[0]=1;
            for(reg i=1;i<=n;++i){
                for(reg j=i;j>=1;--j){
                    g[i][j]=(s[j-1]+(ll)b[i]*c[i-1][j-1])%mod;
                }
                for(reg j=i;j>=1;--j){
                    (t[j]+=t[j-1])%=mod;
                    (s[j]+=g[i][j])%=mod;
                }
            }
    //        for(reg i=1;i<=n;++i){
    //            cout<<" ii "<<a[i]<<endl;
    //            for(reg j=1;j<=i;++j){
    //                cout<<" i j "<<i<<" "<<j<<" ff "<<f[i][j]<<" gg "<<g[i][j]<<endl;
    //            }
    //        }
            ll ans=0;
            for(reg i=0;i<m;++i){
                if(i<k){
                    ans=(ans+(ll)F(i,i)*G(m-i,k-i)%mod)%mod;
                }else{
                    ans=(ans+(ll)F(i,k-1)*G(m-i,1)%mod)%mod;
                }
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/1/9 7:21:30
    */

    手玩出规律

    列出状态

    然后乘法分配律得到答案

    然后求F,G

  • 相关阅读:
    Appium教程
    ES6对象类型判断
    MyBatisPlus的时间段和模糊查询
    一个div中多个元素垂直居中的一种解决办法
    @JsonFormat与@DateTimeFormat注解的使用
    java日期类型对象通过mybatis向数据库中的存取
    Vue.js单向绑定和双向绑定实例分析
    Maven的使用
    如何将本地的项目提交到码云的远程仓库
    Linux CentOS7 的安装
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10242438.html
Copyright © 2011-2022 走看看