2024.11.19 NOIP 模拟赛 题解
T1 战队分配(team)
题意
给定 \(a_{i,j}\;(1\le i,j\le n)\),将 \(\{1,2,\cdots,n\}\) 划分为两个相同大小的子集 \(S_1,S_2\)(保证 \(n\) 为偶数),使 \(\vert f(S_1)-f(S_2)\vert\) 最大,其中 \(f(S)=\sum_{u\in S,v\in S,u<v}a_{u,v}\),求这个最大值,\(n\le1000\),保证 \(a_{i,j}=a_{j,i},a_{i,i}=0\)
分析
令 \(s_i=\sum_{j=1}^n a_{i,j}\),则
由于要使其绝对值最大,即 \(\sum_{u\in S_1}s_u\) 和 \(\sum_{u\in S_2}s_u\) 相差最大,因此将最大的 \(\frac n2\) 个 \(s\) 放入 \(S_1\),剩余放入 \(S_2\) 一定最优
时间复杂度 \(O(n^2)\)
代码:
#include <bits/stdc++.h>
using namespace std;
int n, a[1010][1010];
struct node{long long Sm;int id;} N[1010];
bool Mk[1010];
int main(){
freopen("team.in", "r", stdin);freopen("team.out", "w", stdout);
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; N[i].id = i, ++i)
for (int j = 1; j <= n; ++j)cin >> a[i][j], N[i].Sm += a[i][j];
sort(N + 1, N + n + 1, [](node a, node b){return a.Sm < b.Sm;});
for (int i = 1; i <= n >> 1; ++i)Mk[N[i].id] = 1;
long long C[2]{};
for (int i = 1; i <= n; ++i)
for (int j = i + 1; j <= n; ++j)
if (Mk[i] == Mk[j])C[Mk[i]] += a[i][j];
cout << C[0] - C[1] << endl;
return 0;
}
/*
6
0 4 -6 2 3 -3
4 0 2 -6 0 0
-6 2 0 0 2 2
2 -6 0 0 -1 5
3 0 2 -1 0 -4
-3 0 2 5 -4 0
0
4
0 1 2 2
1 0 8 -3
2 8 0 5
2 -3 5 0
6
*/
T2 货车运输(cargo)
题意
给定 \(n,k\),求 \(\sum_p\sum_q[\sum_{i=1}^n\max(p_i,q_i)=k]\),其中 \(p\) 和 \(q\) 为长度 \(n\) 的排列,\(n\le100,k\le n^2\)
分析
类似 [ABC134F] Permutation Oddness
考虑从小到大将 \(1\sim n\) 依次填入 \(p\) 和 \(q\)(每次将一个数同时填入两个排列)
定义 \((p_i,q_i)\) 为一组,定义一组填完为两个数都填了
令 \(f_{i,x,s}\) 为 将 \(1\sim i\) 填入 \(p\) 和 \(q\),其中填完了 \(x\) 组,且这 \(x\) 组较大值的总和为 \(s\),有 \(i-x\) 组只填了 \(p\),\(i-x\) 组只填了 \(q\),\(n-i-2(i-x)\) 组完全没有填 的方案数
显然 \(f_{0,0,0}=1\),最终答案为 \(f_{n,n,m}\)
考虑从 \(f_{i-1}\) 转移到 \(f_i\)
令 \(yz=i-1-x\),表示 填了 \(1\sim i-1\) 时,只填了 \(p\)(或 \(q\),显然两者数量相同)的数量
令 \(Rs=n-i-2yz\),表示 填了 \(1\sim i-1\) 时,完全没有填的组的数量
有四种转移:
- 两个 \(i\) 填在 \(p\) 和 \(q\) 的同一下标,则新增一个填满的组,其位置有 \(Rs\) 种选择,转移为 \(Rs\cdot f_{i-1,x,s}\rightarrow f_{i,x+1,s+i}\)
- 将一个 \(i\) 与一个只填了 \(p\) 的配对,另一个新增一组只填 \(q\) 的;或一个 \(i\) 与一个只填了 \(q\) 的配对,另一个新增一组只填 \(p\) 的。两种情况的方案数都是 \(yz\cdot Rs\),转移为 \(2\cdot yz\cdot Rs\cdot f_{i-1,x,s}\rightarrow f_{i,x+1,s+i}\)(可以与上一种合并)
- 一个 \(i\) 与一个只填了 \(p\) 的配对,另一个与一个只填了 \(q\) 的配对,新增两个完整的组,且权值都是 \(i+1\),有 \(yz^2\) 种选择,转移为 \(yz^2 \cdot f_{i-1,x,s}\rightarrow f_{i,x+2,s+2i}\)
- 一个 \(i\) 新增一组只填 \(q\) 的,另一个新增一组只填 \(p\) 的,方案数为 \(C_{Rs}^2\),转移为 \(C_{Rs}^2f_{i-1,x,s}\rightarrow f_{i,x,s}\)
时间复杂度 \(O(n^2k)\),空间复杂度 \(O(nk)\),需要滚动数组优化
代码:
#include <bits/stdc++.h>
#define M 1000000007
using namespace std;
int add(int x, int y){x += y;return x >= M? x - M : x;}void sadd(int &x, int y){x += y;if (x >= M)x -= M;}
int mul(int x, int y){return static_cast<long long>(x) * y % M;}
int n, m, f[2][110][10010];
int main(){
freopen("cargo.in", "r", stdin);freopen("cargo.out", "w", stdout);
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
cin >> n >> m; f[0][0][0] = 1;
for (int i = 1, p = 1, q = 0; i <= n; ++i, swap(p, q)){
fill(*(f[p]), *(f[p]) + 110 * 10010, 0);
for (int x = 0; x < i; ++x)
for (int s = 0; s <= m; ++s){
int yz = i - x - 1, Rs = n - x - yz - yz;
if (s + 2 * i <= m)sadd(f[p][x + 2][s + 2 * i], mul(f[q][x][s], mul(yz, yz)));
if (s + i <= m)sadd(f[p][x + 1][s + i], mul(f[q][x][s], mul(add(mul(2, yz), 1), Rs)));
sadd(f[p][x][s], mul(f[q][x][s], mul(Rs, Rs - 1)));
}
}
cout << f[n & 1][n][m] << endl;
return 0;
}
/*
2 4
2
3 7
12
10 80
254719636
10 75
880121070
9 65
881169913
*/
T3 甜果(sugar)
题意
给定 \(b_{1\sim n}\),\(w_{1\sim n}\),有 \(n\) 个变量 \(x_{1\sim n}\) 初始为 \(a_{1\sim n}\),\(n\) 个操作形如 若 \(x_i>x_{b_i}\) 则令 \(x_i\leftarrow x_i+w_i\),其中 \(1\le i\le n\),若 \(n\) 个操作顺序完全随机,求操作过后 \(x_{1\sim n}\) 的期望取模,多测 \(t\le5\times10^5,\sum n\le 5\times10^5\)
分析
显然每个 \(x_i\) 最终只有两种取值,\(a_i\) 或 \(a_i+w_i\)
当 \(x_{b_i}\ge x_i\) 时,显然 \(x_i\) 必取 \(a_i\)
当 \(x_i>x_{b_i}+w_{b_i}\) 时,显然 \(x_i\) 必取 \(a_i+w_i\)
其他情况则取决于 \(x_{b_i}\) 是否加上 \(w_{b_i}\),即此时 \(x_i\) 最终取值为 \(x_i+w_i\) 当且仅当操作序列中 \(b_i\) 在 \(i\) 之前
处理出每个点 \(i\) 到最近的确定取值点(前两类)的距离 \(L_i\)(定义为路径上经过的点数,包括端点),可以证明一定存在
设这 \(L_i\) 个节点在操作序列中的排名分别为 \(v_{1\sim L_i}\)(将其离散化为 \(1\sim L_i\) 的排列),其中 \(v_1\) 为确定取值点的排名,\(L_i\) 为当前处理点的排名
则一个 \(v\) 序列能使 \(b_i\) 加上 \(w_i\),当且仅当 \(v_{L_i}<v_{L_i-1}>v_{L_i-2}<\cdots\)
可以证明,这样的序列个数为 \(L_i!-D_{L_i}\),其中 \(D\) 为错排序列
时间复杂度 \(O(\sum n)\)
代码:
#include <bits/stdc++.h>
#define M 1000000007
#define Fn for (int i = 1; i <= n; ++i)
using namespace std;
int mul(int x, int y){return static_cast<long long>(x) * y % M;}int add(int x, int y){x += y;return x >= M? x - M : x;}
int sub(int x, int y){x -= y;return x < 0? x + M : x;}void sadd(int &x, int y){x = add(x, y);}void smul(int &x, int y){x = mul(x, y);}
int fpw(int x, int y){int ret = 1;for (; y; y >>= 1, smul(x, x))if (y & 1)smul(ret, x);return ret;}
int fc[500010]{1}, ivfc[500010], D[500010]{0, 0, 1};
int n, a[500010], b[500010], w[500010];
int L[500010];//distance(cnt of vertex,include extreme points) to next one bound to happen
int dfs(int k){if (~L[k])return max(0, L[k]);return L[k] = 1 + dfs(b[k]);}
void work(){
cin >> n;Fn cin >> a[i];Fn cin >> b[i];Fn cin >> w[i];
Fn L[i] = a[b[i]] >= a[i]? (int)-1e9 : a[i] > a[b[i]] + w[b[i]]? 1 : -1;Fn L[i] ^ -1 || dfs(i);
Fn cout << add(a[i], L[i] > 0? mul(mul(sub(fc[L[i]], D[L[i]]), ivfc[L[i]]), w[i]) : 0) << " ";cout << '\n';
}
int main(){
freopen("sugar.in", "r", stdin);freopen("sugar.out", "w", stdout);
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
for (int i = 1; i <= 5e5; ++i)fc[i] = mul(fc[i - 1], i);
ivfc[500000] = fpw(fc[500000], M - 2);
for (int i = 499999; ~i; --i)ivfc[i] = mul(ivfc[i + 1], i + 1);
for (int i = 3; i <= 5e5; ++i)D[i] = mul(i - 1, add(D[i - 1], D[i - 2]));
int t;cin >> t;while (t--)work();
return 0;
}
/*
4
4
2 5 5 2
4 2 1 3
3 2 1 4
3
5 4 3
1 1 1
6 6 6
3
5 4 3
2 3 1
1 2 3
5
2 1 3 2 1
5 1 1 3 4
1 3 4 2 4
2 5 6 2
5 4 3
500000009 6 3
3 1 5 2 1
*/
T4 打平就能出线!(qualify)
题意
给定 \(n,m,d,c_{1\sim n},p_{1\sim n},gd_{1\sim n},x_{1\sim s},y_{1\sim s}\)(其中 \(s=\sum_{i=1}^n m-c_i\)),保证 \(m-2\le c_i\le m,p_i\le 3m,(\forall i\ne j,(x_i,y_i)\ne (x_j,y_j)),(\forall 1\le i\le n,c_i+\sum_{j=1}^s([x_j=i]+[y_j=i])=m)\),有序列 \(Sq_{1\sim s}\),对于每个 \(1\le i\le s\):若 \(Sq_i=0\) 则令 \(p_{x_i}\) 和 \(p_{y_i}\) 加 \(1\);若 \(Sq_i<0\),则令 \(p_{y_i}\) 加 \(3\),\(gd_{y_i}\) 加上 \(-Sq_i\);否则令 \(p_{x_i}\) 加 \(3\),\(gd_{x_i}\) 加上 \(Sq_i\)。操作结束后,将所有二元组 \((p_i,gd_i)\) 排序,以 \(p\) 为第一关键字,\(gd\) 为第二关键字,若两者都相同,则顺序任意。求对于所有 \(Sq\),\((p_d,gd_d)\) 最后可能的最大最小排名,\(n,m\le3\times10^5\)
分析
(此题过于变态,\(std\) 长达 \(13k\),赛场上除 \(std\) 外两所学校(联考)只有一人拿了 \(10pts\),其余人都没分,还无法理解题解,暂不订正)
比赛结果
\(20+25+5+0\),近期最惨的一次

浙公网安备 33010602011771号