2024/09/25 模拟赛总结

rk5,100+40+5+0=145。T2 上物理课把式子推出来了,感谢孟德的馈赠

#A. 变换

简单 dp,为什么都写 3 维啊

dpi,j,0/1,0/1 为考虑前 i 位改了 j 位,当前是/不是“山谷”,前一位是/不是“山谷”

显然,相邻两位一定不会都是山谷,所以 dpi,j,1,1 一定不存在

考虑转移。对于 dpi,j,0,0,只要上一位不是“山谷”即可,即 dpi,j,0,0=max{dpi1,j,0,0,dpi1,j,0,1}

对于 dpi,j,0,1,上一位的上一位一定不为“山谷”,所以 dpi,j,0,1=dpi1,j,1,0

对于 dpi,j,1,0,需要分类讨论。若第 i 本来就是“山谷”,则 dpi,j,1,0=ai+max{dpi1,j,0,0,dpi1,j,0,1};否则 dpi,j,1,0=min{ai1,ai+1}1+max{dpi1,j1,0,0,dpi1,j1,0,1}

最终答案为 max{dpn,i,0,0/1}

// BLuemoon_
#include <bits/stdc++.h>

using namespace std;
using LL = long long;

const int kMaxN = 2e3 + 5;

int n, k, tot;
LL ans, a[kMaxN], f[kMaxN][kMaxN][2][2];

int main() {
  freopen("change.in", "r", stdin), freopen("change.out", "w", stdout);
  cin >> n >> k;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
  }
  for (int i = 2; i < n; i++) {
    if (a[i] < a[i + 1] && a[i] < a[i - 1]) {
      for (int j = 0; j <= min(i, k); j++) {
        f[i][j][1][0] = max({f[i - 1][j][0][0], f[i - 1][j][0][1]}) + a[i];
        f[i][j][0][1] = f[i - 1][j][1][0];
        f[i][j][0][0] = max({f[i - 1][j][0][0], f[i - 1][j][0][1]});
      }
    } else {
      for (int j = 0; j <= min(i, k); j++) {
        f[i][j][0][0] = max({f[i - 1][j][0][0], f[i - 1][j][0][1]});
        f[i][j][0][1] = f[i - 1][j][1][0];
        j && (f[i][j][1][0] = max({f[i - 1][j - 1][0][1], f[i - 1][j - 1][0][0]}) + min(a[i - 1], a[i + 1]) - 1);
      }
    }
  }
  for (int j = 0; j <= k; j++) {
    f[n][j][0][0] = max({f[n - 1][j][0][0], f[n - 1][j][0][1]});
    f[n][j][0][1] = max({f[n - 1][j][1][0], f[n - 1][j][1][0]});
  }
  for (int i = 0; i <= k; i++) {
    ans = max({ans, f[n][i][0][0], f[n][i][0][1]});
  }
  cout << ans << '\n';
  return 0;
}

#B. 交替

打表找规律,可以看到系数和组合数有关

那直接省略找规律过程,给出式子:

ans={i=1n2(1)i+1×Cn2i1×a2i1nmod2=1i=1n2(1)i+1×Cn21i1×(a2i1+a2i)else

// BLuemoon_
#include <bits/stdc++.h>

using namespace std;
using LL = long long;

const int kMaxN = 1e5 + 5;
const LL kP = 1e9 + 7;

int n;
LL a[kMaxN], f[kMaxN], ans;

LL P(LL x, LL y, LL ret = 1) {
  for (; y; (y & 1) && ((ret *= x) %= kP), (x *= x) %= kP, y >>= 1) {
  }
  return ret;
}
LL C(LL p, LL k) {
  return f[p] * P(f[k] * f[p - k] % kP, kP - 2) % kP;
}

int main() {
  freopen("alternate.in", "r", stdin), freopen("alternate.out", "w", stdout), f[0] = 1;
  for (int i = 1; i < kMaxN; i++) {
    f[i] = f[i - 1] * i % kP;
  }
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
  }
  if (n & 1 ^ 1) {
    for (int i = 1; i <= (n >> 1); i++) {
      (ans += (P(-1, i + 1) * C((n >> 1) - 1, i - 1) % kP) * (a[i << 1] + a[(i << 1) - 1]) % kP) %= kP, (ans += kP) %= kP;
    }
  } else {
    for (int i = 1; i <= (n >> 1) + 1; i++) {
      (ans += (P(-1, i + 1) * C(n >> 1, i - 1) % kP) * a[(i << 1) - 1] % kP) %= kP, (ans += kP) %= kP;
    }
  }
  cout << ans << '\n';
  return 0;
}

#C. 打拳

首先解决 k=1 的情况,显然只要 1 到树根的路上所有人都是被收买的人即可,考虑状压 dp,令 dpi,j 为已经考虑了前 i 个被收买的人,被被收买的人占据的状态是 j

枚举每个人是否占据每个位置暴力转移即可,具体可以看代码

k1 时,可以 DFS 暴力枚举出所有合法的 LIS 序列,转移时不合法就直接扔掉

// BLuemoon_
#include <bits/stdc++.h>

using namespace std;
using LL = long long;

const int kMaxN = 9 + 2, kMaxM = 16 + 2, kL = 1 << kMaxN, kMaxK = 5e5 + 5;

int n, m, k, tot, ct;
char ch = '0';
string s, str[kMaxK], cur, nxt;
LL kP, a[kMaxM], ans, f[kL], c[kMaxK], C[kL][kL], dp[kMaxM][kMaxK];
unordered_map<string, int> mp, d;
vector<string> cnt;

void DFS(string t, int x) {
  if (mp[t]) {
    return;
  }
  mp[t] = 1, cnt.push_back(t), tot++;
  if (x == n) {
    return;
  }
  for (int i = 0; i < n; i++, ch = '0') {
    if (t[i] == '0') {
      string tmp = t;
      for (int j = 0; j < i; j++) {
        ch = max(ch, t[j]);
      }
      tmp[i] = ch + 1, DFS(tmp, x + 1);
    }
  }
}
LL P(LL x, LL y, LL ret = 1) {
  for (; y; (y & 1) && ((ret *= x) %= kP), (x *= x) %= kP, y >>= 1) {
  }
  return ret;  
}

int main() {
  freopen("box.in", "r", stdin), freopen("box.out", "w", stdout);
  cin >> n >> m >> k >> kP;
  f[0] = f[1] = 1, C[0][0] = C[1][0] = C[1][1] = 1;
  for (int i = 2; i < kL; i++) {
    f[i] = f[i - 1] * i % kP, C[i][0] = 1;
    for (int j = 1; j <= i; j++) {
      C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % kP;
    }
  }
  for (int i = 0; i < m; i++) {
    cin >> a[i];
  }
  sort(a, a + m);
  for (int i = 0; i < n; i++) {
    s += '0';
  }
  DFS(s, 0);
  for (int i = 0; i < tot; i++) {
    s = cnt[i], ch = '0';
    for (int j = 0; j < n; j++) {
      s[j] == '0' ? (s[j] = ch + 1, ch++) : ch = max(ch, s[j]);
    }
    ch = '0';
    for (int j = 0; j < n; j++) {
      ch = max(ch, s[j]);
    }
    if (ch - '0' >= k) {
      str[++ct] = cnt[i], d[cnt[i]] = ct;
    }
  }
  for (int i = 1; i <= ct; i++) {
    for (int j = 0; j < n; j++) {
      (str[i][j] != '0') && (c[i] |= (1 << j));
    }
  }
  dp[0][1] = 1;
  for (int i = 0; i < m; i++) {
    for (int j = 1; j <= ct; j++) {
      if (dp[i][j]) {
        (dp[i + 1][j] += dp[i][j]) %= kP;
        cur = str[j];
        for (int k = 0; k < n; k++) {
          if (cur[k] == '0' && a[i] >= c[j] + (1 << k) + 1) {
            nxt = cur, ch = '0';
            for (int l = 0; l < k; l++) {
              ch = max(ch, nxt[l]);
            }
            nxt[k] = ch + 1;
            (dp[i + 1][d[nxt]] += (dp[i][j] * C[a[i] - c[j] - 2][(1 << k) - 1] % kP * f[1 << k])) %= kP;
          }
        }
      }
    }
  }
  for (int j = 1; j <= ct; j++) {
    (c[j] == ((1 << n) - 1)) && ((ans += dp[m][j]) %= kP);
  }
  cout << ans * (1 << n) % kP << '\n';
  return 0;
}

#D. 扑克

唐氏大模拟

枚举所有可能出现的手牌序列,将其关键牌放到最后面,进行排序,首先比较牌型,否则从后向前比较每张牌的大小

由于皇家同花顺和同花顺本质上是同一种牌型,且直接比较牌的大小也可以区分他们。可以把皇家同花顺直接当作普通同花顺处理即可

两对、一对、高牌可以直接扔掉,因为在可以想象的情况下,你可以想象两张你有的一种点数的两张牌,就至少会有三条了

通过哈希求出所有三张牌序列可以得到的所有牌型,对于每个询问,对哈希序列倍增就可以求出刚刚好比另一个大的牌了

// BLuemoon_
#include <bits/stdc++.h>

using namespace std;

const int kMaxN = 2e5 + 5;

int H(int x) {
  return (x - 1) % 4;
}
int D(int x) {
  return (x - 1) / 4;
}

struct Card {
  int typ, e;
  const bool operator<(const Card& _) {
    return D(typ) != D(_.typ) ? D(typ) < D(_.typ) : H(typ) < H(_.typ);
  }
};
struct Deck {
  int typ;
  Card c[7];
};

Card a, b;
Deck f[kMaxN];
int t, tot;
string str, d = "23456789TJQKA", h = "SHCD";
vector<int> v[kMaxN];

void CardO(Card x) {
  cout << h[H(x.typ)] << d[D(x.typ)] << ' ';
}
void DeckO(Deck x) {
  CardO(x.c[1]), CardO(x.c[2]), CardO(x.c[3]), CardO(x.c[4]), CardO(x.c[5]);
  return cout << '\n', void();
}
bool Chk1(int x, int y) {
  return D(x) + 1 == D(y);
}
bool G2(Deck& x) {
  int T = H(x.c[1].e);
  if (Chk1(x.c[1].e, x.c[2].e) && Chk1(x.c[2].e, x.c[3].e) && Chk1(x.c[3].e, x.c[4].e) && Chk1(x.c[4].e, x.c[5].e) && T == H(x.c[2].e) && T == H(x.c[3].e) && T == H(x.c[4].e) && T == H(x.c[5].e)) {
    x.typ = 2;
    for (int i = 1; i <= 5; i++) {
      x.c[i].typ = x.c[i].e;
    }
    return 1;
  }
  return 0;
}
bool G3(Deck& x) {
  if (D(x.c[2].e) == D(x.c[3].e) && D(x.c[3].e) == D(x.c[4].e)) {
    if (D(x.c[1].e) == D(x.c[2].e)) {
      x.typ = 3, x.c[1].typ = x.c[5].e, x.c[2].typ = x.c[1].e, x.c[3].typ = x.c[2].e, x.c[4].typ = x.c[3].e, x.c[5].typ = x.c[4].e;
      return 1;
    }
    if (D(x.c[4].e) == D(x.c[5].e)) {
      x.typ = 3;
      for (int i = 1; i <= 5; i++) {
        x.c[i].typ = x.c[i].e;
      }
      return 1;
    }
  }
  return 0;
}
bool G4(Deck& x) {
  if (D(x.c[1].e) == D(x.c[2].e) && D(x.c[4].e) == D(x.c[5].e)) {
    if (D(x.c[2].e) == D(x.c[3].e)) {
      x.typ = 4, x.c[1].typ = x.c[4].e, x.c[2].typ = x.c[5].e, x.c[3].typ = x.c[1].e, x.c[4].typ = x.c[2].e, x.c[5].typ = x.c[3].e;
      return 1;
    }
    if (D(x.c[3].e) == D(x.c[4].e)) {
      x.typ = 4;
      for (int i = 1; i <= 5; i++) {
        x.c[i].typ = x.c[i].e;
      }
      return 1;
    }
  }
  return 0;
}
bool G5(Deck& x) {
  int T = H(x.c[1].e);
  if (T == H(x.c[2].e) && T == H(x.c[3].e) && T == H(x.c[4].e) && T == H(x.c[5].e)) {
    x.typ = 5;
    for (int i = 1; i <= 5; i++) {
      x.c[i].typ = x.c[i].e;
    }
    return 1;
  }
  return 0;
}
bool G6(Deck& x) {
  if (Chk1(x.c[1].e, x.c[2].e) && Chk1(x.c[2].e, x.c[3].e) && Chk1(x.c[3].e, x.c[4].e) && Chk1(x.c[4].e, x.c[5].e)) {
    x.typ = 6;
    for (int i = 1; i <= 5; i++) {
      x.c[i].typ = x.c[i].e;
    }
    return 1;
  }
  return 0;
}
bool G7(Deck& x) {
  if (D(x.c[1].e) == D(x.c[2].e) && D(x.c[2].e) == D(x.c[3].e)) {
    x.typ = 7, x.c[1].typ = x.c[4].e, x.c[2].typ = x.c[5].e, x.c[3].typ = x.c[1].e, x.c[4].typ = x.c[2].e, x.c[5].typ = x.c[3].e;
    return 1;
  }
  if (D(x.c[2].e) == D(x.c[3].e) && D(x.c[3].e) == D(x.c[4].e)) {
    x.typ = 7, x.c[1].typ = x.c[1].e, x.c[2].typ = x.c[5].e, x.c[3].typ = x.c[2].e, x.c[4].typ = x.c[3].e, x.c[5].typ = x.c[4].e;
    return 1;
  }
  if (D(x.c[3].e) == D(x.c[4].e) && D(x.c[4].e) == D(x.c[5].e)) {
    x.typ = 7;
    for (int i = 1; i <= 5; i++) {
      x.c[i].typ = x.c[i].e;
    }
    return 1;
  }
  return 0;
}
void JudgeT(Deck& x) {
  if (G2(x) || G3(x) || G4(x) || G5(x) || G6(x) || G7(x)) {
    return;
  }
}
const bool operator<(const Deck& l, const Deck& r) {
  if (l.typ != r.typ) {
    return l.typ < r.typ;
  }
  for (int i = 5; i; i--) {
    if (D(l.c[i].typ) != D(r.c[i].typ)) {
      return D(l.c[i].typ) > D(r.c[i].typ);
    }
  }
  for (int i = 5; i - 1; i--) {
    if (H(l.c[i].typ) != H(r.c[i].typ)) {
      return H(l.c[i].typ) < H(r.c[i].typ);
    }
  }
  return H(l.c[1].typ) < H(r.c[1].typ);
}
int Hash(Card a, Card b, Card c) {
  return a.e * 53 * 53 + b.e * 53 + c.e;
}
int Map(string S, int tp = 0, int cd = 0) {
  tp = (S[0] == 'S' ? 1 : (S[0] == 'H' ? 2 : (S[0] == 'C' ? 3 : 4)));
  if ('2' <= S[1] && S[1] <= '9') {
    return (S[1] - '0' - 2) * 4 + tp;
  }
  cd = (S[1] == 'T' ? 10 : (S[1] == 'J' ? 11 : (S[1] == 'Q' ? 12 : (S[1] == 'K' ? 13 : 14))));
  return (cd - 2) * 4 + tp;
}
const bool operator>(const Deck& l, const Deck& r) {
  if (l.typ != r.typ) {
    return l.typ < r.typ;
  }
  for (int i = 5; i; i--) {
    if (D(l.c[i].typ) != D(r.c[i].typ)) {
      return D(l.c[i].typ) > D(r.c[i].typ);
    }
  }
  return 0;
}

int main() {
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  freopen("poker.in", "r", stdin), freopen("poker.out", "w", stdout);
  for (int i = 1; i <= 52; i++) {
    for (int j = i + 1; j <= 52; j++) {
      for (int k = j + 1; k <= 52; k++) {
        for (int l = k + 1; l <= 52; l++) {
          for (int r = l + 1; r <= 52; r++) {
            f[++tot].c[1].e = i, f[tot].c[2].e = j, f[tot].c[3].e = k, f[tot].c[4].e = l, f[tot].c[5].e = r;
            JudgeT(f[tot]);
            tot -= (f[tot].typ == 0);
          }
        }
      }
    }
  }
  sort(f + 1, f + tot + 1);
  for (int i = 1; i <= tot; i++) {
    v[Hash(f[i].c[1], f[i].c[2], f[i].c[3])].push_back(i);
    v[Hash(f[i].c[1], f[i].c[2], f[i].c[4])].push_back(i);
    v[Hash(f[i].c[1], f[i].c[2], f[i].c[5])].push_back(i);
    v[Hash(f[i].c[1], f[i].c[3], f[i].c[4])].push_back(i);
    v[Hash(f[i].c[1], f[i].c[3], f[i].c[5])].push_back(i);
    v[Hash(f[i].c[1], f[i].c[4], f[i].c[5])].push_back(i);
    v[Hash(f[i].c[2], f[i].c[3], f[i].c[4])].push_back(i);
    v[Hash(f[i].c[2], f[i].c[3], f[i].c[5])].push_back(i);
    v[Hash(f[i].c[2], f[i].c[4], f[i].c[5])].push_back(i);
    v[Hash(f[i].c[3], f[i].c[4], f[i].c[5])].push_back(i);
  }
  for (cin >> t; t; t--, a.e = b.e = a.typ = b.typ = 0) {
    for (int i = 1; i <= 3; i++) {
      cin >> str, (a.e *= 53) += Map(str);
    }
    for (int i = 1; i <= 3; i++) {
      cin >> str, (b.e *= 53) += Map(str);
    }
    if (!(f[v[a.e][0]] > f[v[b.e][0]])) {
      cout << "-1\n";
      continue;
    }
    int cur = 0, sz = v[a.e].size();
    for (int i = 1 << 12; i; i >>= 1) {
      cur += (i * (cur + i < sz && f[v[a.e][cur + i]] > f[v[b.e][0]]));
    }
    Deck tmp = f[v[a.e][cur]];
    sort(tmp.c + 1, tmp.c + 6);
    DeckO(tmp);
  }
  return 0;
}

这个代码的行数和前三题讲解+代码的行数差不多

posted @   BluemoonQwQ  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示