zoukankan      html  css  js  c++  java
  • LOJ2538. 「PKUWC2018」Slay the Spire【组合数学】

    LINK


    思路

    首先因为式子后面把方案数乘上了

    所以其实只用输出所有方案的攻击力总和

    然后很显然可以用强化牌就尽量用

    因为每次强化至少把下面的牌翻一倍,肯定是更优的

    然后就只有两种情况

    • 强化牌数量少于k
    • 强化牌数量大于等于k

    根据乘法原理,设(f_{i,j})是选i张强化牌用j张的倍数总和,(g_{i,j})是选i张攻击用j张的倍数总和

    (ans+=f_{k,k}*g_{m-i,m-k})

    (ans+=f_{i,k-1}*g_{m-i,1})

    然后f的计算可以量化大小这个东西,就是先排序

    dp出选了i个数,最后一个在j的方案数,这样前面的j各种不可能选出其他数,对于后面的数直接组合数计算就可以了


    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int Mod = 998244353;
    
    const int N = 3e3 + 10;
    
    int n, m, k, a[N], b[N], c[N][N];
    int sum[N], f[N][N], g[N][N];
    
    int add(int a, int b) {
      return (a += b) >= Mod ? a - Mod : a;
    } 
    
    int mul(int a, int b) {
      return 1ll * a * b % Mod;
    } 
    
    void init() {
      for (int i = 0; i < N; i++) c[i][0] = 1;
      for (int i = 1; i < N; i++) {
        for (int j = 1; j <= i; j++) {
          c[i][j] = add(c[i - 1][j], c[i - 1][j - 1]);
        }
      }
    }
    
    int calcf(int a, int b) { // 取a张用b张 
      if (a < b) return 0;
      if (!b) return c[n][a]; //**
      int res = 0;
      for (int i = 1; i <= n; i++)
        res = add(res, mul(f[b][i], c[n - i][a - b]));
      return res;
    }
    
    int calcg(int a, int b) {
      if (a < b) return 0;
      if (!b) return 0; //**
      int res = 0;
      for (int i = 1; i <= n; i++) 
        res = add(res, mul(g[b][i], c[n - i][a - b]));
      return res;
    }
    
    void solve() {
      scanf("%d %d %d", &n, &m, &k);
      for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
      for (int i = 1; i <= n; i++) scanf("%d", &b[i]);
      sort(a + 1, a + n + 1, [&](const int a, const int b) {return a > b;});
      sort(b + 1, b + n + 1, [&](const int a, const int b) {return a > b;});
      for (int i = 1; i <= n; i++) {
        f[1][i] = a[i];
        sum[i] = add(sum[i - 1], a[i]);
      }
      for (int i = 2; i <= n; i++) {
        for (int j = i; j <= n; j++)
          f[i][j] = mul(sum[j - 1], a[j]);
        for (int j = 1; j <= n; j++)
          sum[j] = add(sum[j - 1], f[i][j]);
      }
      for (int i = 1; i <= n; i++) {
        g[1][i] = b[i];
        sum[i] = add(sum[i - 1], b[i]);
      }
      for (int i = 2; i <= n; i++) {
        for (int j = i; j <= n; j++) {
          g[i][j] = add(mul(b[j], c[j - 1][i - 1]), sum[j - 1]);
        }
        for (int j = 1; j <= n; j++)
          sum[j] = add(sum[j - 1], g[i][j]);
      }
      int ans = 0;
      for (int i = max(0, m - n); i <= min(n, m); i++) {
        if (i < k) ans = add(ans, mul(calcf(i, i), calcg(m - i, k - i)));
        else ans = add(ans, mul(calcf(i, k - 1), calcg(m - i, 1)));
      }
      printf("%d
    ", ans);
    }
    
    int main() {
    #ifdef dream_maker
      freopen("input.txt", "r", stdin);
    #endif
      init();
      int T; scanf("%d", &T);
      while (T--) solve();
      return 0;
    }  
    
  • 相关阅读:
    Servlet中文件上传
    Servlet 返回Json数据格式
    Java通用oracle和mysql数据库连接
    JAVA JDBC
    Thread suspend()挂起resume()恢复
    Thread 线程池
    阿里巴巴开源框架java诊断工具--Arthas
    B Tree
    MySQL--高性能MySQL笔记二
    MySQL--高性能MySQL笔记一
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/10117453.html
Copyright © 2011-2022 走看看