首页 > 其他分享 >2024/09/26 模拟赛总结

2024/09/26 模拟赛总结

时间:2024-09-27 11:45:01浏览次数:1  
标签:sz 26 int LL 09 2024 mp ans dp

rk4,\(0+30+40+30=100\),T1挂惨了

#A. 智乃的差分

分类讨论,由于 \(a_i\ge0\),当 \(x < 0\) 时,可以直接升序排列

当 \(x > 0\) 时,大部分情况下可以降序排列,但可能会出现 \(a_1=x\) 的情况,就可以找到第一个不为 \(x\) 且不为 \(0\) 的数,swap 掉即可

然后是最麻烦的 \(x=0\),当出现最多的数出现次数大于 \(\lceil\frac{n}{2}\rceil\),一定无解,如果等于,还要分类。如果这个最多的数不是 \(0\),就直接和其他数插空放,如果是 \(0\),当 \(n\) 是偶数时,可以将所有偶数位放 \(0\),其他位插空放,如果时奇数,则无解

否则,由于最大出现次数小于 \(\lceil\frac{n}{2}\rceil\),排序后直接按顺序先放奇数位再放偶数位即可,此时如果第一位等于 \(x\),就把数组 reverse

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

using namespace std;

const int kMaxN = 1e5 + 5;

int t, n, a[kMaxN], c[kMaxN], x, mx = -1, k;
map<int, int> mp;

int main() {
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  freopen("difference.in", "r", stdin), freopen("difference.out", "w", stdout);
  for (cin >> t; t; t--, mp.clear(), mx = -1) {
    cin >> n >> x;
    for (int i = 1; i <= n; i++) {
      cin >> a[i];
    }
    if (n == 1) {
      cout << (x == a[1] ? "no" : "yes") << '\n';
      (x != a[1]) && (cout << a[1] << '\n');
      continue;
    }
    if (x < 0) {
      sort(a + 1, a + n + 1);
    } else if (x > 0) {
      sort(a + 1, a + n + 1, greater<int>());
      bool flag = 1;
      if (a[1] == x) {
        for (int i = 2; i <= n; i++) {
          if (a[i] != a[1]) {
            (a[i] == 0) ? (flag = 1) : (swap(a[1], a[i]), flag = 0);
            break;
          }
        }
        if (flag) {
          cout << "no\n";
          continue;
        }
      }
    } else {
      int e = (n / 2) + (n % 2), v;
      for (int i = 1; i <= n; i++) {
        mp[a[i]]++, (mx < mp[a[i]]) && (mx = mp[a[i]], v = a[i]);
      }
      if (mx > e) {
        cout << "no\n";
        continue;
      }
      if (mx == e) {
        if (v == x) {
          if (n & 1) {
            cout << "no\n";
            continue;
          }
          for (int i = 2; i <= n; i += 2) {
            c[i] = v;
          }
          for (int i = 1, j = 1; i <= n; i += 2, j++) {
            for (; a[j] == v; j++) {
            }
            c[i] = a[j];
          }
          cout << "yes\n";
          for (int i = 1; i <= n; i++) {
            cout << c[i] << ' ';
          }
          cout << '\n';
          continue;
        }
        for (int i = 1; i <= n; i += 2) {
          c[i] = v;
        }
        for (int i = 2, j = 1; i <= n; i += 2, j++) {
          for (; a[j] == v; j++) {
          }
          c[i] = a[j];
        }
      } else {
        sort(a + 1, a + n + 1), k = 1;
        if (a[1] == x) {
          reverse(a + 1, a + n + 1);
        }
        for (int i = 1; i <= n; i += 2, k++) {
          c[i] = a[k];
        }
        for (int i = 2; i <= n; i += 2, k++) {
          c[i] = a[k];
        }
      }
      for (int i = 1; i <= n; i++) {
        a[i] = c[i];
      }
    }
    cout << "yes\n";
    for (int i = 1; i <= n; i++) {
      cout << a[i] << ' ';
    }
    cout << '\n';
  }
  return 0;
}

#B. 牛牛的旅行

比较典的拆贡献题,显然对于总长度和总最大值可以分开解决,总长度可以使用换根 dp,而最大值部分稍麻烦一些

对于每一个点,定义其“影响域”为,一个最大的包含此点的连通块,其内任意路径过此点的两点之间的 \(max_{val}\) 为这个点的权值

然后对于“影响域”内的每一个点,它到“影响域”内其他点路径经过关键点的个数乘上关键点的权值。即令关键点为 \(x\),\(y\) 为“影响域”内与 \(x\) 相连的点,那么 \(x\) 的贡献为 \(\sum (size_{x}-sz_{y})\times sz_{y}\),其中 \(size\) 为“影响域”大小,\(sz\) 为“影响域”内的子树大小

按权值升序排序后计算贡献即可

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

using namespace std;
using LL = long long;

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

struct P {
  LL id, x;
  bool operator<(const P& _) const {
    return x < _.x;
  }
};

int n;
P a[kMaxN];
LL ans, sz[kMaxN], fa[kMaxN];
bool vis[kMaxN];
vector<int> g[kMaxN];

int F(int x) {
  return (fa[x] == x) ? x : (fa[x] = F(fa[x]));
}
void DFS(int u, int fa) {
  sz[u] = 1;
  for (int v : g[u]) {
    if (v != fa) {
      DFS(v, u), sz[u] += sz[v], ans -= sz[v] * (n - sz[v]) % kP, (ans += kP) %= kP;
    }
  }
}

int main() {
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  freopen("tour.in", "r", stdin), freopen("tour.out", "w", stdout);
  cin >> n;
  for (int i = 1, x; i <= n; i++) {
    cin >> x, a[i] = (P){i, x}, fa[i] = i;
  }
  for (int i = 1, u, v; i < n; i++) {
    cin >> u >> v, g[u].push_back(v), g[v].push_back(u);
  }
  DFS(1, 0), sort(a + 1, a + n + 1);
  fill(sz + 1, sz + n + 1, 1);
  for (int u = 1; u <= n; u++) {
    for (int v : g[a[u].id]) {
      if (vis[v]) {
        (ans += (a[u].x * sz[F(a[u].id)] % kP) * sz[F(v)] % kP) %= kP;
        int X = F(a[u].id), Y = F(v);
        (X != Y) && (fa[X] = Y, sz[Y] += sz[X]);
      }
    }
    vis[a[u].id] = 1;
  }
  cout << (ans << 1) % kP << '\n';
  return 0;
}

#C. 第K排列

std 写什么【】矩阵乘法啊,还是我们 csr 有实力

令 \(dp_{i,j}\) 为已经填了 \(i\sim n\) 位,第 \(i\) 位填了 \(j\) 的最大值,直接枚举转移即可

然后由于 \(k\) 只有 \(1000\),我们可以 DFS 暴力枚举所有填数序列,当当前值已经大于 \(k\) 时直接剪枝掉,就可以愉快的卡过去了

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

using namespace std;
using LL = long long;

const int kMaxN = 1e3  + 5;

int n, x, k, a[5][5];
LL dp[kMaxN][5];
map<char, int> mp;
string s, ans, tmp = "NOIP", O = "INOP";

void DFS(int t, LL e) {
  if (t > n) {
    if (e >= x) {
      if (!--k) {
        cout << ans.substr(1) << '\n', exit(0);
      }
    }
    return;
  }
  if (s[t] == '?') {
    for (int i = 3; ~i; i--) {
      LL f = dp[t][i];
      (t > 1) && (f += a[mp[ans[t - 1]]][i]);
      if (f + e >= x) {
        LL cur = e;
        (t > 1) && (cur += a[mp[ans[t - 1]]][i]);
        ans[t] = O[i], DFS(t + 1, cur);
      }
    }
    return;
  }
  int i = mp[s[t]];
  ans[t] = s[t];
  LL f = dp[t][i];
  (t > 1) && (f += a[mp[ans[t - 1]]][i]);
  if (f + e >= x) {
    LL cur = e;
    (t > 1) && (cur += a[mp[ans[t - 1]]][i]);
    ans[t] = O[i], DFS(t + 1, cur);
  }
}

int main() {
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0), mp['I'] = 0, mp['N'] = 1, mp['O'] = 2, mp['P'] = 3;
  freopen("permutation.in", "r", stdin), freopen("permutation.out", "w", stdout);
  cin >> n >> x >> k >> s, s = ' ' + s;
  for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 4; j++) {
      cin >> a[mp[tmp[i]]][mp[tmp[j]]];
    }
  }
  fill(dp[0], dp[kMaxN - 1], -1e18);
  (s[n] == '?') ? (dp[n][0] = dp[n][1] = dp[n][2] = dp[n][3] = 0) : (dp[n][mp[s[n]]] = 0);
  for (int i = n - 1; i; i--) {
    if (s[i] == '?') {
      for (int j = 0; j < 4; j++) {
        for (int k = 0; k < 4; k++) {
          dp[i][j] = max(dp[i][j], dp[i + 1][k] + a[j][k]);
        }
      }
    } else {
      for (int j = 0; j < 4; j++) {
        dp[i][mp[s[i]]] = max(dp[i][mp[s[i]]], dp[i + 1][j] + a[mp[s[i]]][j]);
      }
    }
  }
  ans.resize(n + 1), DFS(1, 0);
  cout << "-1\n";
  return 0;
}

#D. 牛牛的 border

std 写什么【】后缀数组啊,还是我们 csr 有实力

直接大力 SAM,由于两个相同的子串可以唯一确定一个子串的一个 border。所以令每种字符串长度为 \(len\),出现次数为 \(p\),那么它的贡献为 \(len \times \mathrm{C}_{p}^{2}\)

建出 \(link\) 树后进行树形 dp 算式子即可

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

using namespace std;
using LL = long long;

const int kMaxN = 1e5 + 5, kMaxC = 26 + 5;

LL n, ans;

struct SAM {
  struct P {
    LL lnk, maxl, to[kMaxC], sz;
    vector<int> g;
  };
  int tot, lst;
  P s[kMaxN << 1];
  SAM() {
    lst = tot = 0, s[0].maxl = 0, s[0].lnk = -1;
  }
  void Insert(int ch, int c, int p = 0) {
    for (s[c].maxl = s[p = lst].maxl + 1, s[c].sz = 1; (p != -1) && (!s[p].to[ch]); s[p].to[ch] = c, p = s[p].lnk) {
    }
    if (p == -1) {
      return s[lst = c].lnk = 0, void();
    }
    int ed = s[p].to[ch];
    if (s[p].maxl == s[ed].maxl + 1) {
      return s[lst = c].lnk = ed, void();
    }
    for (s[++tot] = s[ed], s[tot].sz = 0, s[tot].maxl = s[p].maxl + 1; (~p) && (s[p].to[ch] == ed); s[p].to[ch] = tot, p = s[p].lnk) {
    }
    s[ed].lnk = s[lst = c].lnk = tot;
  }
  void Update(string str, int sz) {
    for (int i = 0; i < sz; i++) {
      Insert(str[i] - 'a' + 1, ++tot);
    }
  }
  void Link() {
    for (int i = 0; i <= tot; i++) {
      (~s[i].lnk) && (s[s[i].lnk].g.push_back(i), 1);
    }
  }
  void DFS(int u, int fa) {
    for (int v : s[u].g) {
      DFS(v, u), s[u].sz += s[v].sz;
    }
    ans += (s[u].maxl + s[fa].maxl + 1) * (s[u].maxl - s[fa].maxl) * s[u].sz * (s[u].sz - 1) / 4;
  }
};

SAM sam;
string s;

int main() {
  freopen("border.in", "r", stdin), freopen("border.out", "w", stdout);
  cin >> n >> s, sam.Update(s, n), sam.Link(), sam.DFS(0, 0);
  cout << ans << '\n';
  return 0;
}

标签:sz,26,int,LL,09,2024,mp,ans,dp
From: https://www.cnblogs.com/bluemoon-blog/p/18435285

相关文章

  • 20240926 模拟赛总结
    \(10+30+30+10=80\),有挂惨了。比赛链接:http://172.45.35.5/d/HEIGETWO/homework/66f4fec944f0ed11b057cca9或http://172.45.35.5/d/HEIGETWO/homework/66f4fec944f0ed11b057cca9A-智乃的差分题意:给定一个数列\(a_n\)(\(0\lea_i\le10^9\)),你可以重排这个数组,问是否存在一......
  • 2024年10月南京、武汉、深圳NPDP®产品经理认证,学习找我
    在当今这个快速变化的商业环境中,产品创新已成为企业持续发展与竞争的核心动力。为了有效应对市场挑战,提升产品开发效率与质量,越来越多的企业和个人开始关注并投身于专业的产品开发与管理知识体系的学习与实践中。其中,新产品开发专业人员(NPDP)认证作为全球公认的产品开发与管理领域的......
  • 2024年冲刺目标:解锁PMP®项目管理证书,赋能职业新高度
    在快速变化的职场环境中,项目管理作为推动企业高效运作、实现战略目标的关键能力,其重要性日益凸显。随着企业对项目管理专业人才需求的不断增长,拥有国际公认的项目管理专业人士(PMP®)认证已成为许多职场人士提升竞争力、拓宽职业道路的重要途径。如果你正计划在2024年底前考取PMP®项......
  • Oracle 19c OCP 认证考试 083 题库(第37题)- 2024年修正版
    【优技教育】Oracle19cOCP083题库(Q37题)-2024年修正版考试科目:1Z0-083考试题量:85道(线下)通过分数:57%以上考试时间:150min(线下)本文为(CUUG原创)整理并解析,转发请注明出处,禁止抄袭及未经注明出处的转载。原文地址:http://www.cuug.com.cn/ocp/083kaoshitiku/38365593598.h......
  • 【2024最新版】超详细Burpsuite安装保姆级教程-适合入门小白
    在CTF比赛中或者是抓包中我们都会用到一个工具Burpsuite,但是有很多小伙伴们刚入门安全,不知道该如何去安装这个Burpsuite,今天我就来教大家如何安装Burpsuite第一次使用先按照下面的教程激活,激活后无需再次激活下载链接极核GetShell在下载链接下方,我们可以选择windows和Linux......
  • YOLOv9改进,YOLOv9主干网络替换为GhostNetV3(2024年华为提出的轻量化架构,全网首发),助力
    摘要GhostNetV3是由华为诺亚方舟实验室的团队发布的,于2024年4月发布。摘要:紧凑型神经网络专为边缘设备上的应用设计,具备更快的推理速度,但性能相对适中。然而,紧凑型模型的训练策略目前借鉴自传统模型,这忽略了它们在模型容量上的差异,可能阻碍紧凑型模型的性能提升。在本......
  • 汇付天下2024北京服务商生态合作峰会盛大举行
    继广州站、成都站成功举办,9月25日,以“数智新生长,汇见新未来”为主题的2024汇付服务商生态合作峰会-北京站盛大启幕。众多汇付服务商、生态伙伴等齐聚一堂,共商数字生态下的新增长、共绘数字时代的新蓝图。汇付天下助理总裁高亮山参会并致辞。他首先对来自全国各地的新老朋友......
  • 【2024-09-26】共频童真
    20:00在人生的旅途中,我们也许会遗失很多美好、遭遇许多挫折,我们可以失望,可以失败,但绝不能绝望,不能放弃!一切都可以重新开始,因为明天是新的一天了!                                         ......
  • ABC262G 题解
    LISwithStack观察到\(n\le50\),考虑区间dp。设\(dp(l,r,x,y)\)表示区间\([l,r]\)中选出的子序列的最小值\(\gex\),最大值\(\ley\)的方案数。根据栈的性质,设元素\(x\)入栈的时间为\(in_x\),出栈时间为\(out_x\),那么所有元素构成的区间\([in_x,out_x]\)两......
  • P10681 COTS/CETS 2024 奇偶矩阵 Tablica
    P10681COTS/CETS2024奇偶矩阵Tablica来自qnqfff大佬的梦幻dp。约定二元组\((n,m)\)表示一个\(n\)行\(m\)列的矩形。不添加说明的子问题,限制与题面一致。思路先考虑放最后一行,发现你填的位置经过变换后可以得到其他的结果,也就是说只要乘上变换的方案数就可以任......