2025-12-28noip模拟测验总结
拿了 \(100 + 65 + 100 + 100 = 365\),rank 2。
膜拜 george AK %%%。
T1 冒泡排序
见过结论()
题意简述
有 \(T(T \leq 10^5)\) 次询问,每次给定 \(n(n \leq 10^7)\),求长为 \(n\) 的随机排列期望最少 swap 多少次可以有序。
题解
结论:\(ans_i = i - \sum\limits_{j = 1}^i \frac{1}{j}\)。
参考代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') f = -1;
ch = getchar();
}
while(isdigit(ch)){
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
inline void write(int x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
return;
}
inline int fp(int a, int b, int p){
int res = 1;
while(b){
if(b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
const int Mod = 998244353;
int inv[10000005], ans[10000005];
//ans[i] = i - (1/1 + 1/2 + ... + 1/i)
inline void init(){
inv[1] = 1;
for(int i = 2; i <= 1e7; i++){
inv[i] = Mod - Mod / i * inv[Mod % i] % Mod;
ans[i] = ((ans[i - 1] + 1 - inv[i]) % Mod + Mod) % Mod;
}
return;
}
signed main(){
init();
int T = read();
while(T--) write((ans[read()] % Mod + Mod) % Mod), putchar('\n');
return 0;
}
T2 情报中心
以为能过就没上 bitset(\kk
题意简述
给定一张 \(n\) 个点,\(m\) 条边的 \(1\) 权图,共有 \(q\) 次询问,每次给定 \(k\) 组 \((u, d)\),表示距 \(u\) 不超过 \(d\) 的点都是好的,求出每次询问好的点的个数。
数据范围:\(1 \leq n,q \leq 1000\),\(1 \leq m \leq 10^5\),\(1 \leq \sum k \leq 2 \times 10^6\)。
题解
记 \(v_{u, d}\) 表示距离 \(u\) 不超过 \(d\) 的点的集合。
显然,可以通过 \(n\) 次 bfs 求出所有 \(v\)(这是 \(1\) 权图)。
此时,使用 bitset 按位或运算即可。
时间复杂度会除个 \(w\),然后就过了。
参考代码:
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("inline")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fstrict-aliasing")
#include<bits/stdc++.h>
// #define int long long
using namespace std;
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') f = -1;
ch = getchar();
}
while(isdigit(ch)){
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
inline void write(int x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
return;
}
bitset<1005> v[1005][1005], res;
vector<int> e[1005];
int n, m;
queue<pair<int, int> > q;
int vis[1005];
inline void bfs(int s){
while(!q.empty()) q.pop();
memset(vis, 0, sizeof(vis));
q.push({s, 0}), vis[s] = true;
while(!q.empty()){
int u = q.front().first, d = q.front().second;
q.pop();
v[s][d][u] = 1;
for(auto v : e[u]){
if(!vis[v]){
vis[v] = true;
q.push({v, d + 1});
}
}
}
return;
}
signed main(){
n = read(), m = read(); int qq = read();
for(int i = 1; i <= m; i++){
int u = read(), v = read();
e[u].push_back(v), e[v].push_back(u);
}
for(int i = 1; i <= n; i++) bfs(i);
for(int u = 1; u <= n; u++){
for(int d = 1; d <= n; d++){
v[u][d] |= v[u][d - 1];
}
}
while(qq--){
int k = read();
res.reset();
for(int i = 1; i <= k; i++){
int u = read(), d = read();
res |= v[u][d];
}
write(res.count()), putchar('\n');
}
return 0;
}
T3 百鸽笼
怎么还有板子题(
题意简述
维护一个序列,支持如下操作:
-
把序列最左边的那个数扬了
-
在序列最左边插入一个数
-
查询区间第 \(k\) 小
保证 \(n, q \leq 10^5, |V| \leq 10^9\),256 MB。
题解
主席树板子啊,第二个操作和建主席树的操作一样。
注意卡卡空间。
参考代码:
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("inline")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fstrict-aliasing")
#include<bits/stdc++.h>
// #define int long long
using namespace std;
bool ST;
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') f = -1;
ch = getchar();
}
while(isdigit(ch)){
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
inline void write(int x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
return;
}
int n, q, a[200005], b[400005], rt[400005], tot;
struct Ask{
int op;
int l, r, k;
}ask[400005];
struct SegT{
int ls, rs;
int sum;
}t[20000005];
inline void build(int &p, int l, int r){
if(!p) p = ++tot;
if(l == r) return;
int mid = (l + r) >> 1;
build(t[p].ls, l, mid), build(t[p].rs, mid + 1, r);
return;
}
inline void modify(int &p, int yuanp, int x, int PL, int PR){
if(x < PL || x > PR) return;
p = ++tot;
t[p] = t[yuanp], t[p].sum++;
if(x <= PL && PR <= x) return;
int mid = (PL + PR) >> 1;
modify(t[p].ls, t[yuanp].ls, x, PL, mid), modify(t[p].rs, t[yuanp].rs, x, mid + 1, PR);
return;
}
inline int query(int pl, int pr, int k, int PL, int PR){
if(PL == PR) return PL;
int cntl = t[t[pr].ls].sum - t[t[pl].ls].sum;
int mid = (PL + PR) >> 1;
if(cntl >= k) return query(t[pl].ls, t[pr].ls, k, PL, mid);
return query(t[pl].rs, t[pr].rs, k - cntl, mid + 1, PR);
}
bool ED;
signed main(){
// freopen("input.in", "r", stdin);
// freopen("output.out", "w", stdout);
n = read(), q = read();
int btot = 0;
for(int i = 1; i <= n; i++) a[i] = b[++btot] = read();
for(int i = 1; i <= q; i++){
ask[i].op = read();
if(ask[i].op == 1){
//
}else if(ask[i].op == 2){
ask[i].k = read();
b[++btot] = ask[i].k;
}else{
ask[i].l = read(), ask[i].r = read(), ask[i].k = read();
}
}
sort(b + 1, b + 1 + btot);
int V = unique(b + 1, b + 1 + btot) - b - 1;
for(int i = 1; i <= n; i++){
a[i] = lower_bound(b + 1, b + 1 + V, a[i]) - b;
}
for(int i = 1; i <= q; i++){
if(ask[i].op == 2){
ask[i].k = lower_bound(b + 1, b + 1 + V, ask[i].k) - b;
}
}
// for(int i = 1; i <= n; i++) cout << a[i] << ' ';
// cout << '\n' << V << '\n';
build(rt[0], 1, V);
for(int i = 1; i <= n; i++) modify(rt[i], rt[i - 1], a[n - i + 1], 1, V);
int nowr = n;
for(int i = 1; i <= q; i++){
if(ask[i].op == 1){
nowr--;
}else if(ask[i].op == 2){
modify(rt[nowr + 1], rt[nowr], ask[i].k, 1, V);
nowr++;
}else{
int r = nowr - ask[i].l + 1, l = nowr - ask[i].r + 1;
// cout << l << ' ' << r << '\n';
write(b[query(rt[l - 1], rt[r], ask[i].k, 1, V)]), putchar('\n');
}
}
// cerr << 1.0 * (&ED - &ST) / 1024.0 / 1024.0 << " MB" << '\n';
return 0;
}
T4 方块
感觉不难,为啥只有两个人过这题(
题意简述
赛后被翻出原题了:https://www.luogu.com.cn/problem/UVA1030。
题解
考虑贪心,每次从近到远删方块即可。
时间复杂度大概是 \(\mathcal{O}(Tn^4)\) 的(?)
#include<bits/stdc++.h>
using namespace std;
int n;
string view[10][20];
char cube[20][20][20];
// 从左到右,从上到下,从前到后
inline tuple<int, int, int> calc(int s, int r, int c, int t){
if(s == 1) return {c, r, t};
else if(s == 2)return {t, r, n - c + 1};
else if(s == 3) return {n - c + 1, r, n - t + 1};
else if(s == 4) return {n - t + 1, r, c};
else if(s == 5) return {c, t, n - r + 1};
else if(s == 6)return {c, n - t + 1, r};
return {-1, -1, -1};
}
inline void Solve(){
for(int i = 1; i <= n; i++){
for(int s = 1; s <= 6; s++){
cin >> view[s][i];
view[s][i] = ' ' + view[s][i];
}
}
for(int x = 1; x <= n; x++){
for(int y = 1; y <= n; y++){
for(int z = 1; z <= n; z++){
cube[x][y][z] = '#';
}
}
}
for(int s = 1; s <= 6; s++){
for(int x = 1; x <= n; x++){
for(int y = 1; y <= n; y++){
if(view[s][x][y] == '.'){
for(int t = 1; t <= n; t++){
auto [xx, yy, zz] = calc(s, x, y, t);
cube[xx][yy][zz] = '.';
}
}
}
}
}
bool changed = true;
while(changed){
changed = false;
for(int s = 1; s <= 6; s++){
for(int x = 1; x <= n; x++){
for(int y = 1; y <= n; y++){
char want = view[s][x][y];
if(want == '.') continue;
// 近 -> 远
for(int t = 1; t <= n; t++){
auto [xx, yy, zz] = calc(s, x, y, t);
if(cube[xx][yy][zz] == '.') continue;
if(cube[xx][yy][zz] == '#'){
cube[xx][yy][zz] = want;
changed = true;
break;
}
if(cube[xx][yy][zz] == want) break;
cube[xx][yy][zz] = '.', changed = true;
}
}
}
}
}
int ans = 0;
for(int x = 1; x <= n; x++){
for(int y = 1; y <= n; y++){
for(int z = 1; z <= n; z++){
if(cube[x][y][z] != '.'){
ans++;
}
}
}
}
cout << "Maximum weight: " << ans << " gram(s)" << '\n';
return;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
while(cin >> n && n) Solve();
return 0;
}
/*
3
.R. YYR .Y. RYY .Y. .R.
GRB YGR BYG RBY GYB GRB
.R. YRR .Y. RRY .R. .Y.
2
ZZ ZZ ZZ ZZ ZZ ZZ
ZZ ZZ ZZ ZZ ZZ ZZ
0
*/

浙公网安备 33010602011771号