• 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;
    }
    
  • 相关阅读:
    DLL导出类避免地狱问题的完美解决方案
    WorldWind源码剖析系列:影像图层类ImageLayer
    WorldWind源码剖析系列:插件类Plugin、插件信息类PluginInfo和插件编译器类PluginCompiler
    多线程中的锁系统(一)-基础用法
    [转]分布式计算框架综述
    C#自定义控件开发
    GDI+编程小结
    C#自定义控件
    WorldWind源码剖析系列:窗口定制控件类WorldWindow
    WorldWind源码剖析系列:四叉树瓦片集合类QuadTileSet
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9912345.html
Copyright © 2020-2023  润新知