当前位置: 首页 > news >正文

20251011 总结

P9870 [NOIP2023] 双序列拓展

首先有一个暴力做法。

翻译一下题意,即为:

图片

拓展也就是一个DP,我们设朴素DP,每次判断能否往下拓展,设fij表示x匹配到第i位,y匹配到第j位。

然后考虑特殊性质:

图片

也就是说,这个特殊性质就是两个框往左上扫,扫到左上即可,

图片

然后考虑正解,X最小值和Y最大值的位置不再固定,但是发现左上和右下可以独立考虑

图片

#include <bits/stdc++.h>
using namespace std;const int N = 5e5 + 5;int f[N], g[N];struct Node {int min, max;Node(int ge = 0, int fe = 0) : min(ge), max(fe) {}
};Node preX[N], preY[N], sufX[N], sufY[N];inline Node update_node(int T[], const Node &p, int i) {return Node(T[i] < T[p.min] ? i : p.min, T[i] > T[p.max] ? i : p.max);
}bool check1(int x, int y, int n, int m) {if (x == 1 || y == 1) return true;Node X = preX[x - 1], Y = preY[y - 1];if (f[X.min] < g[Y.min]) return check1(X.min, y, n, m);if (g[Y.max] > f[X.max]) return check1(x, Y.max, n, m);return false;
}bool check2(int x, int y, int n, int m) {if (x == n || y == m) return true;Node X = sufX[x + 1], Y = sufY[y + 1];if (f[X.min] < g[Y.min]) return check2(X.min, y, n, m);if (g[Y.max] > f[X.max]) return check2(x, Y.max, n, m);return false;
}bool solve(int tmpf[], int tmpg[], int n, int m) {if (tmpf[1] >= tmpg[1]) return false;for (int i = 1; i <= n; i++) f[i] = tmpf[i];for (int i = 1; i <= m; i++) g[i] = tmpg[i];for (int i = 1; i <= n; i++)preX[i] = (i == 1) ? Node(1, 1) : update_node(f, preX[i - 1], i);for (int i = 1; i <= m; i++)preY[i] = (i == 1) ? Node(1, 1) : update_node(g, preY[i - 1], i);for (int i = n; i >= 1; i--)sufX[i] = (i == n) ? Node(n, n) : update_node(f, sufX[i + 1], i);for (int i = m; i >= 1; i--)sufY[i] = (i == m) ? Node(m, m) : update_node(g, sufY[i + 1], i);Node X = preX[n], Y = preY[m];if (f[X.min] >= g[Y.min] || g[Y.max] <= f[X.max]) return false;return check1(X.min, Y.max, n, m) && check2(X.min, Y.max, n, m);
}int tx[N], ty[N], ttx[N], tty[N];int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int dummy, n, m, q;cin >> dummy >> n >> m >> q;for (int i = 1; i <= n; i++) cin >> tx[i];for (int i = 1; i <= m; i++) cin >> ty[i];cout << (solve(tx, ty, n, m) || solve(ty, tx, m, n) ? '1' : '0');while (q--) {for (int i = 1; i <= n; i++) ttx[i] = tx[i];for (int i = 1; i <= m; i++) tty[i] = ty[i];int cx, cy;cin >> cx >> cy;while (cx--) {int p, v;cin >> p >> v;ttx[p] = v;}while (cy--) {int p, v;cin >> p >> v;tty[p] = v;}cout << (solve(ttx, tty, n, m) || solve(tty, ttx, m, n) ? '1' : '0');}return 0;
}

P6817 [PA 2013] Filary

图片

基础模拟赛有类似的题。

首先有一个性质,发现m=2时k是一定大于n/2的,所以答案下界是这个

所以任意一个数,在答案内的概率大于1/2

所以就随机选一个,其他数与他差分,我们要选尽可能多的数使它们的GCD大于1

直接枚举GCD不行。

图片

这里写错了,是预处理最大质因子即可。

#include<bits/stdc++.h>
using namespace std;constexpr int maxn = 1e5+10, maxm = 1e7+10;
int n;
int a[maxn], b[maxn], pri[maxm], tot;
int lpf[maxm];
bool vis[maxm];
mt19937 rnd(114514);void getprime(int n){for(int i = 2;i <= n;i++){if(!vis[i]) pri[++tot] = i;for(int j = 1;j <= tot && i * pri[j] <= n;j++){vis[i * pri[j]] = true;if(i % pri[j] == 0) break;}}for(int i = 1;i <= tot;i++){for(int j = pri[i];j <= n;j += pri[i]) lpf[j] = pri[i];}
}pair<int,int> slove(){int pos = rnd() % n + 1;map<int,int> mp;for(int i = 1;i <= n;i++){b[i] = abs(a[i] - a[pos]);int c = b[i];while(c > 1){int d = lpf[c];mp[d]++;while(c % d == 0) c /= d;}}int mx = 0, ans = 0;for(auto [x, y] : mp) mx = max(mx,y);for(auto [x,y] : mp){if(y == mx){int res = 0;for(int i = 1;i <= n;i++){if(b[i] % x == 0) res = gcd(res,b[i]);}ans = max(ans,res);}}return{mx + count(b+1,b+n+1,0),ans};
}int main(){ios::sync_with_stdio(0);cin.tie(0);cin>>n;for(int i = 1;i <= n;i++) cin>>a[i];getprime(*max_element(a + 1, a + n + 1));pair<int,int> res(0, 0);while((double)clock() / CLOCKS_PER_SEC < 1.3) res = max(res, slove());cout << res.first << ' ' << res.second << '\n';return 0;
}

P4757 [CERC2014] Parades

图片

转移很奇怪的树形DP

首先设f[i]表示以i为根的子树的最优解。

根据这一类套路,肯定是DP过程中保存是否往父亲放边的。

首先有一个结论,就是如果根是关键点,根往儿子连边(牺牲一条u-son)一定不劣于牺牲两条u-son,匹配儿子的两个线头的。

所以DP时维护un[son][i]表示儿子son当前网上接的第i个线头。

然后DP时先优先匹配root和一个带线头的儿子,然后把儿子子树的线头都清理掉(因为已经用掉了)

然后考虑其他儿子,很难DP,考虑状压。

先预处理link[x][y]=true/false表示儿子x和y是否有连边。

然后直接状压DP。

#include <bits/stdc++.h>
using namespace std;const int N = 1010;
const int D = 15;int T, n, m;
int dp[N];         
int f[1<<D];            
int cnt, head[N], nxt[N<<1], to[N<<1]; 
bool vis[N][N];         
vector<int> un[N];      int parentArr[N], depthArr[N], sz[N], heavy[N], top[N], dfn[N], rnkNode[N], timerHLD;int lowbit(int x) { return x & -x; }void init_all() {cnt = 0;memset(head, 0, sizeof(head));memset(vis, 0, sizeof(vis));memset(dp, 0, sizeof(dp));timerHLD = 0;for (int i = 0; i < N; ++i) {parentArr[i] = depthArr[i] = sz[i] = heavy[i] = top[i] = dfn[i] = rnkNode[i] = 0;heavy[i] = -1;}
}void adde(int u, int v) {to[++cnt] = v;nxt[cnt] = head[u];head[u] = cnt;
}void hld_dfs1(int u, int fa) {parentArr[u] = fa;depthArr[u] = (fa ? depthArr[fa] + 1 : 0);sz[u] = 1;int maxsz = 0;for (int e = head[u]; e; e = nxt[e]) {int v = to[e];if (v == fa) continue;hld_dfs1(v, u);sz[u] += sz[v];if (sz[v] > maxsz) {maxsz = sz[v];heavy[u] = v;}}
}void hld_dfs2(int u, int topf) {top[u] = topf;dfn[u] = ++timerHLD;rnkNode[timerHLD] = u;if (heavy[u] != -1) {hld_dfs2(heavy[u], topf);}for (int e = head[u]; e; e = nxt[e]) {int v = to[e];if (v == parentArr[u] || v == heavy[u]) continue;hld_dfs2(v, v);}
}int lca(int a, int b) {while (top[a] != top[b]) {if (depthArr[top[a]] < depthArr[top[b]]) swap(a, b);a = parentArr[top[a]];}return depthArr[a] < depthArr[b] ? a : b;
}void solve_dfs(int u, int fa) {int son[D], tot = 0;for (int e = head[u]; e; e = nxt[e]) {int v = to[e];if (v == fa) continue;solve_dfs(v, u);dp[u] += dp[v];       if (tot < D) son[tot++] = v; }for (int i = 0; i < tot; ++i) {int ch = son[i];for (int j = 0; j < (int)un[ch].size(); ++j) {int x = un[ch][j];if (vis[x][u]) {dp[u]++;         un[ch].clear();  break;         }}}static bool link[D][D];for (int i = 0; i < tot; ++i)for (int j = 0; j < tot; ++j)link[i][j] = false;for (int i = 0; i < tot; ++i) {for (int j = i + 1; j < tot; ++j) {int a = son[i], b = son[j];bool found = false;for (int p = 0; p < (int)un[a].size(); ++p) {for (int q = 0; q < (int)un[b].size(); ++q) {if (vis[un[a][p]][un[b][q]]) {link[i][j] = link[j][i] = true;found = true;break;}}if (found) break;}}}int maxMask = (1 << tot) - 1;f[0] = 0;for (int mask = 1; mask <= maxMask; ++mask) {f[mask] = f[mask & (mask - 1)];int a = __builtin_ctz(mask);for (int b = a + 1; b < tot; ++b) {if ( ((mask >> b) & 1) && link[a][b] ) {int newmask = mask ^ (1<<a) ^ (1<<b);f[mask] = max(f[mask], f[newmask] + 1);}}}dp[u] += f[maxMask]; un[u].clear();un[u].push_back(u);for (int i = 0; i < tot; ++i) {if (f[maxMask] == f[maxMask ^ (1<<i)]) {for (int x : un[son[i]]) un[u].push_back(x);}}
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cin >> T;while (T--) {init_all();cin >> n;for (int i = 1; i <= n; ++i) un[i].clear();for (int i = 1; i < n; ++i) {int u, v;cin >> u >> v;adde(u, v);adde(v, u);}hld_dfs1(1, 0);hld_dfs2(1, 1);cin >> m;for (int i = 0; i < m; ++i) {int u, v;cin >> u >> v;vis[u][v] = vis[v][u] = true;}solve_dfs(1, 0);cout << dp[1] << '\n';}return 0;
}

图片

http://www.hskmm.com/?act=detail&tid=29063

相关文章:

  • 上课讲的部分 qoj 题记录
  • var与let
  • CSP-S 第二轮集训资料 **总结 + 专题细分精讲**_from_黄老师
  • AI元人文:迈向正负价值统一的文明架构
  • CSP-S 第二轮集训资料 **总结 + 专题细分精讲**。
  • 对抗训练提升产品搜索技术解析
  • Ubuntu Linux双网口主机实现在校园网环境下的网络共享
  • C# Avalonia 16- Animation- ExpandElement
  • DshanPI-A1 RK3576 armbian远程桌面
  • Docker安装MQTT
  • Ubuntu Linux双网卡实现在校园网环境下的网络共享
  • PVE8.x仅克隆虚拟机配置
  • 常用的sql语句
  • SQL常用语句分类及示例
  • 台式机主板上的电池要更换啦
  • 微信小程序 app.js中onLaunch中方法执行完毕后再执行index首页数据请求
  • 轻量服务器Lighthouse + 1Panel 部署.NET 8 Web应用
  • bash alias 多引号问题
  • 关于近期调研各类游戏开发引擎的一些感想
  • Electron38-Vue3OS客户端OS系统|vite7+electron38+arco桌面os后台管理
  • 终于在vim中用上了molokai的炫酷色彩配置了(゚∀゚)
  • 我是如何在Vim8.1中安装好的NERDTree插件的
  • Kafka监控工具 EFAK-AI 介绍
  • 视频拍摄技巧 - 希区柯克变焦/滑动变焦 All In One
  • 信息化说课-教学设计(6)
  • 记录:git
  • 实验1 现代C++编程初体验
  • 10.11总结
  • 2025年10月门窗十大品牌最新推荐榜单,十大品牌测评排名与选择指南
  • CF60E Mushroom Gnomes