1. 程式人生 > >UOJ22. 【UR #1】外星人【DP】【思維】

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('\n');
  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;
}