2025-11-12 ZYZ28-NOIP-aoao round 2 hetao1733837的record
比赛链接:比赛详情 - ZYZ28-NOIP-aoao round 2 - ZYZOJ
比赛背景
昨天双十一,ZYZ著名NOI Cu选手@[TaoRan](用户详情 - TaoRan - ZYZOJ)爆出了惊天大瓜——ZYZ著名NOISC Ag选手@[ydtz](用户详情 - ydtz - ZYZOJ)初中时的恋爱博客!一下为节选片段……
${\color{Grey}她的手好软,糯糯地,比我之前握过的一切东西都要软;}$
${\color{Grey}她的手好凉,让我原本多多少少因为中考而有些燥热的心情瞬间冷静下来;}$
${\color{Grey}她的手好小,小到我的手可以将它完全包住,不留一丝空隙。}$
${\color{Grey}那一刻,我的脑中只剩下了一个念头一一这,是我的女人。}$
A.empty
提交链接:题目详情 - 空 - ZYZOJ
原题链接:[P1627 CQOI2009]中位数-洛谷
分析
虽然场切了吧,但是显然做过原题,所以还是复盘一下思路。就是说中位数实际就是$b$在一个序列中,比$b$大的和比$b$小的数量相同,那么又由于题目是在排列的背景下,要求子序列,所以,找到$b$的位置,扩展即可。这里还是以前提到的Trick,就是大于某个数的看成1,小于的
正解
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, b, a[N];
map<int, int> mp;
int main(){freopen("empty.in", "r", stdin);freopen("empty.out", "w", stdout);cin >> n >> b;int pos;for (int i = 1; i <= n; i++){cin >> a[i];if (a[i] == b){pos = i;}}int cnt = 0;for (int i = pos; i <= n; i++){if (a[i] > b)cnt++;if (a[i] < b)cnt--;mp[cnt]++;}int ans = 0;cnt = 0;for (int i = pos; i >= 1; i--){if (a[i] > b)cnt++;if (a[i] < b)cnt--;ans += mp[0 - cnt];}cout << ans;
}
B.purple
提交链接:题目详情 - 紫 - ZYZOJ
原题链接:[P9178 COCI 2022/2023#5] Diskurs - 洛谷
方法一
分析
其实就是一个性质,对于$hamming(x,y)$,若$z$是$x$按位取反的数,那么$hamming(x,y)+hamming(z,y)=m$。那么问题得到了转化,
求$\max\limits_{1\leq j \leq n}hamming(a_i,a_j)$即求$\min\limits_{1\leq j \leq n}hamming(\neg a_i,a_j)$!
那么,考虑建图,把$hamming$函数为1的两个数之间连边,相当于一个数到$a$中所有数的最短距离。直接$bfs$即可。甚至不需要建图 ,只需要位运算即可。
正解
#include <bits/stdc++.h>
using namespace std;
const int M = 20;
int a[(1 << M) + 5], cnt[(1 << M) + 5];
int n, m;
int main(){freopen("purple.in", "r", stdin);freopen("purple.out", "w", stdout);cin >> n >> m;memset(cnt, 0xc0, sizeof(cnt));queue<pair<int, int>> q;for (int i = 1; i <= n; i++){cin >> a[i];cnt[a[i]] = 0;q.push({a[i], cnt[a[i]]});}while (!q.empty()){auto tmp = q.front();q.pop();int p = tmp.first, w = tmp.second;for (int i = 0; i < m; i++){int k = p ^ (1 << i);if (cnt[k] == 0xc0c0c0c0){cnt[k] = w + 1;q.push({k, cnt[k]});}}}for (int i = 1; i <= n; i++){cout << m - cnt[(1 << m) - 1 ^ a[i]] << " ";}
}
方法二
来自@[mahaihang1](用户详情 - mahaihang1 - ZYZOJ)
分析
我们发现,$O(n2)$是好做的,因为*__builtin_popcount*复杂度是$O(1)$的,那我暴力匹配即可。这样,我们对序列去重,设此时长度为*K*,可以跑*2e4*左右。那么对于K大于*2e4*的情况,答案一定不会很小,所以,倒序枚举*m*,可以做到$O(2mK)$。但是,实际复杂度更优,其中$2^m$大概最多跑1e3左右,那么复杂度就来到了1e7左右,甚至更优 /jy
歪解
#include <bits/stdc++.h>
using namespace std;
const int N = 2000005;
int n, m, a[N], ans[N], res[N], len, mk[N];
vector<int> v[30];
signed main(){freopen("purple.in", "r", stdin);freopen("purple.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> m;for (int i = 0; i < (1 << m); i++) v[__builtin_popcount(i)].push_back(i);for (int i = 1; i <= n; i++){cin >> a[i];ans[i] = a[i];mk[a[i]] = 1;} sort(a + 1, a + 1 + n);len = unique(a + 1, a + 1 + n) - a - 1;if (len <= 10000){for (int i = 1; i <= len; i++){for (int j = i + 1; j <= len; j++){res[a[i]] = max(res[a[i]], __builtin_popcount(a[i] ^ a[j]));res[a[j]] = max(res[a[j]], __builtin_popcount(a[i] ^ a[j]));}}}else{for (int i = 1; i <= len; i++){for (res[a[i]] = m; res[a[i]] > 0; res[a[i]]--){int f = 0;for (int x : v[res[a[i]]]){if (mk[a[i] ^ x]){f = 1;break;}}if (f) break;}}}for (int i = 1; i <= n; i++) cout << res[ans[i]] << " ";return 0;
}
C.flower
提交链接:题目详情 - 花 - ZYZOJ
原题链接1:[AT_agc001_e [AGC001E] BBQ Hard]([AT_agc001_e AGC001E] BBQ Hard - 洛谷)
原题链接2:[E - BBQ Hard](E - BBQ Hard)
分析
看来aoao还是比较人性的,居然给出了形式化的题面,直接要求程序快速求解$$\sum\limits_{i=1}{n}\sum\limits_{j=1}\binom{a_i+a_j+b_i+b_j}{a_i+a_j}$$即可。
那么,原式计算的时间复杂度是$O(n^2)$的,接受不了,考虑转化为组合意义(呃,原题的组合意义似乎不太能用)。
我们设$n=a_i+a_j,m=b_i+b_j$将其转化为$\binom{m+n}{n}$,这种东西我们是有套路的,可以直接转化为从$(0,0)$到$(m,n)$只能向上或向右走的方案数。但是,式子还是与$i$与$j$同时相关,那么,我们考虑将其转化为从$(-a_i,-b_i)$到$(a_j,b_j)$的方案数。那么讲所有$(-a_i,-b_i)$位置$+1$,然后只需知道所有$(a_j,b_j)$位置的和即可。那么直接$O(V^2)$DP求解即可(V是值域)。还需要减掉$(-a_i,-b_i)$到$(a_j,b_j)$的贡献(组合数),最后答案乘$\frac{1}{2}$即可。
我会了……吗?似乎并非,还是看代码吧……
正解
#include <bits/stdc++.h>
#define int long long
#define mod 998244853 //注意模数
using namespace std;
const int N = 200005, V = 5000, K = 2500;
int inv = (mod + 1) / 2;
int n, a[N], b[N], fac[N], dp[V][V], ans;
int qpow(int a, int b){int res = 1;while (b){if (b & 1){res = res * a % mod;}a = a * a % mod;b >>= 1;}return res;
}
int calc(int x, int y){return fac[x] * qpow(fac[y] * fac[x - y] % mod, mod - 2) % mod;
}
signed main(){freopen("flower.in", "r", stdin);freopen("flower.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n;for (int i = 1; i <= n; i++){cin >> a[i] >> b[i];dp[K - a[i]][K - b[i]]++;}fac[0] = 1;for (int i = 1; i < N; i++){fac[i] = fac[i - 1] * i % mod;}for (int i = 1; i < V; i++){for (int j = 1; j < V; j++){dp[i][j] = (dp[i][j] + dp[i - 1][j] + dp[i][j - 1]) % mod;}}for (int i = 1; i <= n; i++){ans = (ans + dp[K + a[i]][K + b[i]] - calc(2 * (a[i] + b[i]), 2 * a[i]) + mod) % mod;}cout << ans * inv % mod;
}
但是,如果你直接在AtCoder上提交,会发现WA掉了,为什么呢?因为😈aoao改了模数,一方面为了卡掉题解,另一方面998244353,998244853是容易搞混的,曾经有人因此差点G掉,因此,放在此处以警示后人。
AtCoder正解
#include <bits/stdc++.h>
#define int long long
#define mod 1000000007 //注意模数
using namespace std;
const int N = 200005, V = 5000, K = 2500;
int inv = (mod + 1) / 2;
int n, a[N], b[N], fac[N], dp[V][V], ans;
int qpow(int a, int b){int res = 1;while (b){if (b & 1){res = res * a % mod;}a = a * a % mod;b >>= 1;}return res;
}
int calc(int x, int y){return fac[x] * qpow(fac[y] * fac[x - y] % mod, mod - 2) % mod;
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n;for (int i = 1; i <= n; i++){cin >> a[i] >> b[i];dp[K - a[i]][K - b[i]]++;}fac[0] = 1;for (int i = 1; i < N; i++){fac[i] = fac[i - 1] * i % mod;}for (int i = 1; i < V; i++){for (int j = 1; j < V; j++){dp[i][j] = (dp[i][j] + dp[i - 1][j] + dp[i][j - 1]) % mod;}}for (int i = 1; i <= n; i++){ans = (ans + dp[K + a[i]][K + b[i]] - calc(2 * (a[i] + b[i]), 2 * a[i]) + mod) % mod;}cout << ans * inv % mod;
}
D.float
提交链接:题目详情 - 浮 - ZYZOJ
原题链接1:[CF2162H Beautiful Problem](CF2162H Beautiful Problem - 洛谷)
原题链接2:H. Beautiful Problem
分析
原式想取$1$,则$x$要么$\ge \max\limits_{j=l}{r}a_j$要么$\le\min\limits_{j=l}a_j$,那么,每个位置会属于四种情况——①只被$\ge$覆盖;②只被$\le$覆盖;③被两种同时覆盖;④不被覆盖。呃剩下的我就不太会了,粘一下STD……
STD
#include <bits/stdc++.h>
using namespace std;
const int N = 2010, inf = 0x3f3f3f3f;
int t, n, m, a[N], dp[N][N][2], c[N], idx;
vector<int> v[N];
struct node{int l, r;
}q[N];
signed main(){freopen("float.in", "r", stdin);freopen("float.out", "w", stdout); ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);idx = 0;cin >> n >> m;for (int i = 1; i <= n; i++){c[i] = 0;v[i].clear();} for (int i = 1; i <= n; i++) cin >> a[i];for (int i = 1; i <= m; i++){int l, r;cin >> l >> r;v[l].push_back(r);}int maxr = 0;for (int i = 1; i <= n; i++){if (v[i].empty()) continue;sort(v[i].begin(), v[i].end());if (v[i].back() <= maxr) continue;maxr = v[i].back();q[++idx] = (node){i, maxr};c[i]++;c[maxr + 1]--;}for (int i = 0; i <= idx; i++){for (int j = 0; j <= n; j++){dp[i][j][0] = dp[i][j][1] = -inf; } } dp[1][0][1] = q[1].r - q[1].l + 1;dp[1][q[1].r - q[1].l + 1][0] = 0;for (int i = 2; i <= idx; i++){int len = q[i].r - q[i].l + 1, x = max(0, q[i - 1].r - q[i].l + 1);for (int j = 0; j <= n; j++){if (j - len + x >= 0) dp[i][j][0] = max(dp[i][j][0], dp[i - 1][j - len + x][0]);if (j-len+x>=0) dp[i][j][0] = max(dp[i][j][0], dp[i - 1][j - len + x][1] - x);dp[i][j][1] = max(dp[i][j][1], dp[i - 1][j][1] + len - x);if (j + x <= n) dp[i][j][1] = max(dp[i][j][1], dp[i - 1][j + x][0] + len - x);}}int cnt = 0;for (int i = 1; i <= n; i++){c[i] += c[i - 1];cnt += (!c[i]);} for (int i = 1; i <= n; i++){int sum[2] = {0, 0}, ans = 0;for (int j = 1; j <= n; j++){if (a[j] == i) continue;sum[a[j] > i]++;}for (int j = 0; j <= n; j++){int k = max(dp[idx][j][0], dp[idx][j][1]);ans |= ((sum[0] <= j && sum[1] <= k) || (max(0, sum[0] - j) + max(0, sum[1] - k) <= cnt));}cout << ans;}return 0;
}
原题是多测,需要改一下。
Codeforces正解
#include <bits/stdc++.h>
using namespace std;
const int N = 2010, inf = 0x3f3f3f3f;
int t, n, m, a[N], dp[N][N][2], c[N], idx;
vector<int> v[N];
struct node{int l, r;
}q[N];
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int T;cin >> T;while (T--){idx = 0;cin >> n >> m;for (int i = 1; i <= n; i++){c[i] = 0;v[i].clear();} for (int i = 1; i <= n; i++) cin >> a[i];for (int i = 1; i <= m; i++){int l, r;cin >> l >> r;v[l].push_back(r);}int maxr = 0;for (int i = 1; i <= n; i++){if (v[i].empty()) continue;sort(v[i].begin(), v[i].end());if (v[i].back() <= maxr) continue;maxr = v[i].back();q[++idx] = (node){i, maxr};c[i]++;c[maxr + 1]--;}for (int i = 0; i <= idx; i++){for (int j = 0; j <= n; j++){dp[i][j][0] = dp[i][j][1] = -inf; } } dp[1][0][1] = q[1].r - q[1].l + 1;dp[1][q[1].r - q[1].l + 1][0] = 0;for (int i = 2; i <= idx; i++){int len = q[i].r - q[i].l + 1, x = max(0, q[i - 1].r - q[i].l + 1);for (int j = 0; j <= n; j++){if (j - len + x >= 0) dp[i][j][0] = max(dp[i][j][0], dp[i - 1][j - len + x][0]);if (j-len+x>=0) dp[i][j][0] = max(dp[i][j][0], dp[i - 1][j - len + x][1] - x);dp[i][j][1] = max(dp[i][j][1], dp[i - 1][j][1] + len - x);if (j + x <= n) dp[i][j][1] = max(dp[i][j][1], dp[i - 1][j + x][0] + len - x);}}int cnt = 0;for (int i = 1; i <= n; i++){c[i] += c[i - 1];cnt += (!c[i]);} for (int i = 1; i <= n; i++){int sum[2] = {0, 0}, ans = 0;for (int j = 1; j <= n; j++){if (a[j] == i) continue;sum[a[j] > i]++;}for (int j = 0; j <= n; j++){int k = max(dp[idx][j][0], dp[idx][j][1]);ans |= ((sum[0] <= j && sum[1] <= k) || (max(0, sum[0] - j) + max(0, sum[1] - k) <= cnt));}cout << ans;}cout << '\n';}return 0;
}
OK,完结,撒花★,°:.☆( ̄▽ ̄)/$:.°★ 。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/963655.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!