zoukankan      html  css  js  c++  java
  • UOJ22. 【UR #1】外星人【DP】【思维】

    LINK


    题目大意

    给你一个序列和一个值x

    问你用某种方式对序列安排顺序之后一次对x取mod的最大值和方案数

    首先发现一个性质

    • 一个数之后所有比它大的数都没有贡献

    考虑怎么利用这个性质?

    就可以从小到大插入每一个数

    然后就开开心心的发现每次插入的数如果有贡献一定是在第一个,否则可以在任意位置

    然后就可以非常自然地令(f_{i,j})表示初始数是i,放入前j个数的最大值

    然后转移就是枚举当前有没有贡献(f[i][j] = max(f[i][j - 1], f[i\% a[j]][j - 1]))

    注意特判边界

    然后第一问就做完了

    考虑第二问,(g_{i,j})表示初始数是i,放入前j个并到达当前最优状态的最大值

    每次直接判断两个值是一样大还是一个比另一个更大,累加贡献就可以啦


    注意i是0也要算方案数哦!


    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    typedef pair<int, int> pi;
    typedef long long ll;
    typedef double db;
    #define fi first
    #define se second
    #define fu(a, b, c) for (int a = b; a <= c; ++a)
    #define fd(a, b, c) for (int a = b; a >= c; --a)
    #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x;
      }
      if (x > 9) Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    const int N = 5e3 + 10;
    const int Mod = 998244353;
    int n, x, a[N];
    int 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;
    }
    
    int main() {
    #ifdef dream_maker
      freopen("input.txt", "r", stdin);
    #endif
      Read(n), Read(x);
      fu(i, 1, n) Read(a[i]);
      sort(a + 1, a + n + 1);
      fu(i, 0, x) f[i][0] = i;
      fu(i, 0, x)
        fu(j, 1, n) {
          if (j == 1) f[i][j] = i % a[j];
          else f[i][j] = max(f[i][j - 1], f[i % a[j]][j - 1]);
        } 
      Write(f[x][n]), putchar('
    ');
      fu(i, 0, x) g[i][1] = 1;
      fu(i, 0, x) {
        fu(j, 2, n) {
          g[i][j] = 0;
          if (f[i][j - 1] >= f[i % a[j]][j - 1]) {
            g[i][j] = add(g[i][j], mul(g[i][j - 1], j - 1));
          }
          if (f[i][j - 1] <= f[i % a[j]][j - 1]) {
            g[i][j] = add(g[i][j], g[i % a[j]][j - 1]);
          }
        }
      } 
      Write(g[x][n]);
      return 0;
    }
    
  • 相关阅读:
    常用并发类
    线程基本知识
    java多线程基础
    volatile原理小结
    condition学习小结
    阻塞队列、线程池、异步
    Synchronized原理
    wait 和notify
    【Java 8 新特性】Java Comparator.comparing | 提取对象属性,按照指定规则排序
    在Centos8上配置Minio服务使用TLS
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9912345.html
Copyright © 2011-2022 走看看