题目难度按照个人主观划分,代码冗杂烦请见谅
签到 : ACH
mid:MLEK
hard:FG
题意:
小 A 有一个高度为 h 的长方形盒子。他把这个盒子放在一张桌子上,并建立了一个三维直角坐标系 O−xyz ,其中桌子位于 z=z0。
由于小 A 患有强迫症,他将盒子的长和宽分别平行于 x 和 y 轴(长不一定对应于 x 轴),底面有一对对角顶点,分别位于 (u0,v0,z0) 和 (u1,v1,z0) 。
现在小 A 有 q 个查询。对于每个查询,他都会提供一个点 (xi,yi,zi),并希望知道该点是否在方框内(边界也被视为在方框内)。
思路:判断是否在体内,看是否在左下角和右上角两个点范围之内即可,模拟
// Code Start Here
int z0 , z1 , x0 , y0 , x1 , y1;
cin >> z0 >> z1 >> x0 >> y0 >> x1 >> y1;
if(x0 > x1)swap(x0,x1);
if(y0 > y1)swap(y0,y1);
z1 += z0;
int q;
cin >> q;
while(q--){
int x , y , z;
cin >> x >> y >> z;
if(x >= x0 && x <= x1 && y >= y0 && y <= y1 && z >= z0 && z <= z1)cout <<"Yes\n";
else cout <<"No\n";
}
return 0;
题意:给定一个由大写字母组成的字符串 S ,请重新排列 S 中的字符顺序,使子串 CCPC 作为连续的子串出现尽可能多的次数。请确定 CCPC 的最大可能出现次数。
思路:观察到最优解是尽可能高效率的使用C与P,每个CCPC固定一个P,而另外的C可以看公共前后缀,如CCPCCPC即:每个P配对两个C最后多余一个C 模拟即可
// Code Start Here
string s;
cin >> s;
map<char,int> mp;
for(int i = 0;i<sz(s);i++)mp[s[i]]++;
cout << min(mp['P'] , (mp['C'] - 1) / 2) <<endl;
return 0;
题意:
小 A 有一个只包含字符 `0` 和 `1` 的字符串(以下简称 01 字符串)。他喜欢 `1`,不喜欢 `0`,所以在小 A 的眼里,01 字符串中只有 `1`。
具体来说,对于 01 字符串,小 A 认为 `0` 是一个分隔符,它把字符串分成几个完全由 `1` 组成的子串。例如,对于 01 字符串 `010011101111101`,小 A 会看到四个仅由 `1` 组成的子串:`1`、`111`、`11111` 和 `1`。
对于 01 字符串,小 A 将其**魅力值**定义为完全由 `1` 组成的分隔子串长度的**平方根之和**。例如,对于 `010011101111101` 这个字符串,小 A 的魅力值为:
√1 + √3 + √5 + √1 = 2 + √3 + √5
现在,给你一个 01 字符串 `s`,小 A 希望你能将 `s` 中的一些 `1` 改为 `0`(或保持不变),以**最大化**这个 01 字符串的魅力值。
思路:我们注意到对于平方根开根,越大的数亏损越大。
几个例子是:
1-1 亏损0
2-1.414 亏损0.5+
3-1.732 亏损 1+
4-2 亏损 2+
所以尽可能的,将连续的1的子序列,将其转化为单独个分割。注意到长度为奇数的,可以直接变成1-1-1。而偶数个前面与奇数个处理相同,在最后可以留出来一个2直接加入贡献,不必再变成01
// Code Start Here
string s;
cin >> s;
deque<int> dq;
for(int i = 0;i<sz(s);i++){
dq.push_back(s[i] - '0');
}
vector<int> ans;
while(!dq.empty()){
int cnt = 0;
while(!dq.empty() && dq.front() == 0)dq.pop_front();
while(!dq.empty() && dq.front() == 1)cnt++,dq.pop_front();
if(cnt)ans.push_back(cnt);
}
double d = 0;
for(int num : ans){
if(num == 1)d+=num;
if(num == 2)d+=(sqrt2(num));
if(num >= 3){
if(num % 2 == 1){
d += num / 2;
d ++;
}
else{
d += (num - 2) / 2;
d += sqrt2(2);
}
}
}
cout << point(15) << d << endl;
return 0;
题意:
给定一棵有 n 个节点的树,可以用任意长度的几条线段来覆盖树的所有边,要求如下:
- 每条边必须精确覆盖一次;
- 每条线段必须从叶节点开始,在其一个祖节点结束。
您可以选择任意数量的线段,使这些线段能够按照上述要求覆盖整棵树,但您需要尽量减少线段的最大长度。你的任务就是找出这个最小值。
思路:观察到题目要求“线段最大长度的最小值” ,考虑二分的可行性。
根据树的性质,树的最长路径有n-1条边,因此最坏情况不会超过n-1,最好情况可能是0,所以可以在0~n-1之间猜一个中间值L,然后验证是否可以完成覆盖,如果可以则保留找最小的,否则舍去。观察到题目数据范围2e5且为树结构,每个点在一次遍历中做多被访问一次,Onlogn在允许范围之内。因此二分的想法可以被接受
根据题目的定义,一个可以被接受的活动线段被如下定义:
1.从叶子出发沿着路径一直延伸到当前节点,还没有结束
2.在内部节点,由于要求每个节点最多只能有一条延伸到父节点的活动线段,其余的线段必须在该节点结束。
为了验证某个 L 是否可行,我们设计一个 DFS 函数,从树的叶子开始往上计算活动线段的长度。对每个节点 u 计算一个值,表示从该节点向上延伸的、未结束的线段的长度。这里的长度是指从最初的叶子节点到当前节点经过的边数。
对于叶节点本身无孩子,因此可以作为一条目前长度为0的线段的起点
对于树的内部节点:当一个内部节点 u 有多个孩子时,每个孩子都会传递上来一个延伸值,这个值代表从该孩子的子树中选出的、延伸到孩子位置的线段长度。对于每个孩子 v,我们先得到孩子那边的“活动线段”的长度,然后加1(表示经过边 u 到 v 的这条边)。记录这个值为dfs + 1
如果有任何一个超过了L,说明需要舍弃。
而在内部节点 u,只能有一条线段继续延伸向上传递到父节点,其余的都必须在 u 结束。考虑怎么选择延伸的线段。为了最小化L,我们假设当前节点孩子传递上来a , b两个线段,a < b,这个节点自己能往上走h,a + h < b + h,所以为了最小化L明显选择较短的继续延伸,而其他孩子的线段,将在这里结束。
同时,我们也记录所有孩子传递上来的候选值的最大值。如果最大的候选值超过 L,则整个子树方案无效,返回 INF。
// Code Start Here
int t;
cin >> t;
while(t--){
int n;
cin >> n;
vector<vector<int>> child(n+1);
for(int i = 2;i<=n;i++){
int u;
cin >> u;
child[u].push_back(i);
}
auto dfs = [&](auto dfs , int u , int l)->int{
if(child[u].empty())return 0;
int min_val = INF;
int max_val = -INF;
for(int v : child[u]){
int ret = dfs(dfs , v , l);
if(ret == INF)return INF;
if(ret + 1 > l)return INF;
min_val = min(min_val,ret + 1);
max_val = max(max_val,ret + 1);
}
if(max_val > l)return INF;
return min_val;
};
auto check = [&](int l)->bool{
return dfs(dfs , 1 , l) != INF;
};
int l = 0 , r = n - 1 , ans = r;
while( l <= r){
int mid = (l + r ) >> 1;
if(check(mid))ans = mid , r = mid - 1;
else l = mid + 1;
}
cout << ans << endl;
}
return 0;
题意:
小Y想玩一种由四种基本积木组成的拼图游戏,如上图所示。小 Y 有 A,B,C,D 块这四种积木。现在他想用尽可能多的积木拼成一个长方形(长方形或正方形)。问题是,他最多可以用多少块积木?
拼成的长方形必须满足以下条件:
- 任意两个相邻的基本积木必须形成凹凸结构;
- 所形成矩形的四条边缘不得有任何突出或凹陷;
与常见的益智游戏不同,本游戏中的积木没有图案,相同类型的积木被视为完全相同。
思路:首先观察到必须构造四个角,少于4无解
剩下的边界部分分布在矩形的四边。假设矩形的长为 W、宽为 H,那么每条边去掉两个角后:
-
上下各有 W–2 个;
-
左右各有 H–2 个。
总共需要 2(W + H – 4) 个边界块。
这部分只能使用 b 和 c 块,并且它们必须交替使用,这意味着:
-
b 和 c 块的使用数一定要相等。
-
因此,每种块在边上各需要 (W + H – 4) 个。
我们令x=H−2,y=W−2,那么边界上需要的 b 或 c 块数就是 x+y
内部区域完全由 d 块填充,面积为 x * y
所以拼成的矩形总共使用的块数为(x + 2 )*(y + 2)
由于 x 和 y 都是非负整数,并且受到边界块使用数的限制:x + y ≤ min(B, C)我们可以枚举 x 的所有可能值(从 0 到 min(B, C)),然后对每个 x 找到最大的 y 值,使得:
x + y ≤ min(B, C),即对于固定的 x,y 的最大值不能超过 min(B, C) - x。
x × y ≤ D,即对于固定的 x,y 还必须满足:y ≤ ⌊D / x⌋(当 x > 0 时)若 x = 0,则内部面积为 0,直接使用边界条件即可。
由于矩形的面积 (x+2)(y+2) 随着 y 的增大而增大,因此在满足两个条件的情况下,我们应尽量选择最大的 y。
// Code Start Here
int t;
cin >> t;
while(t--){
int a , b , c , d;
cin >> a >> b >> c >> d;
if(a < 4){
cout << 0 << endl;
continue;
}
int l = min(b , c);
int ans = 0;
for(int x = 0;x<=l;x++){
int y ;
if(x == 0)y = l;
else y = min(l - x , d / x);
int s = (x + 2) * (y + 2);
ans = max(ans , s);
}
cout << ans << endl;
}
题意:
给定一棵有根的树,树上有 n 个节点,根节点为 1 ,满足 pi<i 属性,其中 pi 是 i 的父节点。
对于每个节点 u 及其所有子节点 v ,我们将提供只考虑 v 和 v 子树中的节点所形成的新树的中心点索引,注意我们不会提供 v 的索引。如果一棵树有两个中心点,我们会告诉你在原始树中较深的那个。你的任务是构建一棵满足上述条件的树。
树的中心点如果从树中选择并移除某个节点,树就会被分成几个子树。计算每个子树上的节点数,并记录最大值。考虑到树中的所有节点,最大值最小的节点称为整棵树的中心点。
思路:注意到pi < i,当我们从编号最大的节点开始处理时,一个节点 i 的所有子树中的节点都是比 i 大的。也就是说,在倒序处理时, i 的子树部分已经被处理并归并成若干个连通块
我们考虑使用并查集维护当前已经构造好的连通块,每个连通块对应一个已经构造好的子树。让每个连通块find函数返回的值始终保持为该连通块中最小的结点。
当我们从 n 倒序枚举到 1 时,假设我们正在处理节点 i,那么对于 i 在输入中给出的每个数字 x,且x 来自于某个“子树”中,而且 x > i。此时我们已经处理过比 i 大的节点,所以 x 所在的连通块已经构造好了,通过并查集的 find 操作可以得到这个连通块的根r。代表了孩子 v 的入口,那么可以直接连边(i,r)。这样连接以后,就把节点 i 和这个子树联通起来了。
// Code Start Here
struct DSU{
vector<int> p;
DSU(int n) : p(n+1) {for (int i = 0; i <= n; i++)p[i] = i;}
int find(int a) {
if (p[a] != a)p[a] = find(p[a]);
return p[a];
}
void merge(int a, int b) {
int pa = find(a), pb = find(b);
if(pa < pb)swap(pa , pb);
p[pa] = pb;
}
};
int t;
cin >> t;
while(t--){
int n;
cin >> n;
VVI req(n+1);
for (int i = 1; i <= n; i++){
int cnt;
cin >> cnt;
req[i].resize(cnt);
for (int j = 0; j < cnt; j++){
cin >> req[i][j];
}
}
VPII ans;
ans.reserve(n-1);
DSU dsu(n);
for (int i = n; i >= 1; i--){
for (int x : req[i]) {
int r = dsu.find(x);
ans.push_back({i, r});
dsu.merge(i, r);
}
}
for(PII e : ans)cout << e.fi << " " << e.se <<endl;
}
return 0;
题意:
给定一个非负整数序列 a1, a2, ..., an 和一个常数 k。
我们要求有多少个 x ∈ [0, k] 使得序列
a1 ⊕ x, a2 ⊕ x, ..., an ⊕ x
是非递减的(即每个相邻元素满足 a_i ⊕ x ≤ a_{i+1} ⊕ x)。
思路:
思考如何判断 a_i ⊕ x ≤ a_{i+1} ⊕ x。考虑相邻两个数 u = a_i 和 v = a_{i+1},根据位运算的性质,不妨令b = u ⊕ x, c = v ⊕ x。对于任意两个整数,比较大小时,从最高位开始找第一处不同的比特。设在位运算 m 处 u 与 v 首次不同,则有:
1.若 u[m] = 0, v[m] = 1,那么无论后面的比特如何,原本 u < v;
2.若 u[m] = 1, v[m] = 0,则 u > v。
但在经过 XOR 之后,比特 m 处变为:
b[m] = u[m] ⊕ x[m], c[m] = v[m] ⊕ x[m]
我们要求 b ≤ c,那么决定性位 m 必须满足:
-
如果 u[m] = 0, v[m] = 1(原本 u < v),那么:
-
当 x[m] = 0 时,b[m] = 0, c[m] = 1,条件满足;
-
当 x[m] = 1 时,b[m] = 1, c[m] = 0,条件 不 满足。
-
-
如果 u[m] = 1, v[m] = 0(原本 u > v),则情况反过来:
-
当 x[m] = 0 时,b[m] = 1, c[m] = 0,不满足;
-
当 x[m] = 1 时,b[m] = 0, c[m] = 1,满足。
-
因此,对于每对相邻的 a_i 和 a_{i+1}(若二者不相等),我们可以确定一个 必选约束:
-
设 m 为 a_i 与 a_{i+1} 最高不同的位的位置。如果:
-
a_i[m] = 0, a_{i+1}[m] = 1,则要求 x[m] = 0;
-
a_i[m] = 1, a_{i+1}[m] = 0,则要求 x[m] = 1。
-
如果对于不同的相邻对在同一位上有冲突的要求,则不存在符合条件的 x;否则,我们就得到对某些位 i 的固定要求。
令 dp[i][j] 表示从第 i 位(从最高位 L-1 开始编号,往下到 0)开始,在是否“已经小于” k 的约束下有多少种选择。
参数 j 表示到目前为止是否已经与 k 的前面部分相等。
对于当前位 i:
-
若 now[i] ≠ -1,则只能选这一固定值 d;
-
否则可以枚举 d = 0, 1。
若当前 j = 1 则选的 d 还需满足 d ≤ K[i](其中 K[i] 表示 k 在第 i 位的数字)。将所有状态累加,最后得到的方案数即为答案。
// Code Start Here
auto high = [&](int d)->int{
if(d == 0)return -1;
int pos = 63 - __builtin_clzll(d);
return pos;
};
int t;
cin >> t;
while(t--){
int n , k;
cin >> n >> k;
vector<int> a(n);
for(int i = 0;i<n;i++)cin >> a[i];
int l = 61;
vector<int> ctr(l , -1);
bool f = true;
for(int i = 0;i<n-1;i++){
if(a[i] == a[i+1])continue;
int d= a[i] ^ a[i+1];
int hi = high(d);
int req;
if(((a[i] >> hi) & 1LL) == 0 && ((a[i+1] >> hi) & 1LL) == 1 )req = 0;
else req = 1;
if(ctr[hi] == -1)ctr[hi] = req;
else if(ctr[hi] != req){
f = false;
break;
}
}
if(!f)cout << 0 << endl;
else{
int f[70][2];
for (int i = 0; i <= l; i++) {
f[i][0] = f[i][1] = 0;
}
f[0][1] = 1;
vector<int> bit(l,0);
for(int i = 0;i<l;i++){
bit[i] = (k >> (l-1-i)) & 1;
}
for(int i = 0;i < l;i++){
for(int j = 0;j<2;j++){
if(f[i][j] == 0)continue;
else{
int now = l - 1 - i;
if(ctr[now] != -1){
int d = ctr[now];
if(j == 1){
if(d > bit[i])continue;
}
int jj = j;
if(j == 1&& d<bit[i])jj = 0;
f[i+1][jj] += f[i][j];
}
else{
for (int d = 0; d < 2; d++){
if(j==1 && d > bit[i]) continue;
int jj = j;
if(j==1 && d < bit[i]) jj = 0;
f[i+1][jj] += f[i][j];
}
}
}
}
}
cout << f[l][0] + f[l][1] << endl;
}
}
return 0;
本题使用vector进行dp可能会触发神秘小惊喜导致tle
题意:给出一个长度为n的正整数序列a,求所有序列d满足di|ai 且 di 的乘积为完全平方数的乘积开方之和
思路:题解给的答案是背包DP+拆分,这里给出一种数学的做法
论证:
记原序列为 a_1, ..., a_n。对于每个 a_i 我们可以选一个约数 d_i(必满足 d_i | a_i)。设
d_i = ∏ p^(f_{i,p}), 0 ≤ f_{i,p} ≤ e_{i,p} (其中 a_i = ∏ p^(e_{i,p}))。
因此组合的乘积
x = ∏_{i=1}^{n} d_i = ∏ p^(∑_{i=1}^{n} f_{i,p})。
要求 x 为完全平方,即对每个质数 p 有
∑_{i=1}^{n} f_{i,p} 为偶数。
同时若 x = y^2 则
y = ∏ p^(1/2 * ∑_{i=1}^{n} f_{i,p})。
我们要求对所有满足条件的组合求
S = ∑_{valid (d_1, ..., d_n)} y, 取模 10^9+7。
对于固定质数 p(出现在某些 a_i 中),对每个 a_i 分解得到其 p 的指数 e_i;在 a_i 中允许选 f_i 满足 0 ≤ f_i ≤ e_i(若 p 不整除 a_i 则视为 e_i = 0,贡献 1,不影响后续)。因此对于质数 p 在所有 a_i 上总贡献为
S_p = ∑_{(f_1, ..., f_n)} ∏ p^(1/2 * ∑_{i=1}^{n} f_{i,p}),
其中 ∑ f_i 为偶数。
注意到由于各 a_i 独立,此和可以写成乘积形式。事实上,对每个 a_i(固定 p)构造多项式
G_i(z) = ∑_{f=0}^{e_i} p^(f/2) * z^(f mod 2)。
那么要求所有组合中满足 ∏ z^(f_i mod 2) 中 z^0(偶数个奇次)部分的系数。利用标准技巧,“偶项和 = (G(1) + G(-1)) / 2”,我们可得
S_p = (∏_{i=1}^{n} G_i(1) + ∏_{i=1}^{n} G_i(-1)) / 2。
注意到对每个 a_i(关于质数 p),令
F(e) = G(1) = ∑_{f=0}^{e} p^(f/2),
F(-e) = G(-1) = ∑_{f=0}^{e} (-1)^f * p^(f/2)。
不难发现把奇数项分开写更方便。令
f(e) = ∑_{j=0}^{⌊e/2⌋} p^j,
g(e) =
若 e ≥ 1, 则 ∑_{j=0}^{⌊(e-1)/2⌋} p^j,
若 e = 0, 则 0
那么可以证明
∑_{f=0}^{e} p^(f/2) = f(e) + p * g(e)。
即对每个 a_i(关于质数 p),令
F(e) = f(e) + p * g(e)。
因此
∏_{i=1}^{n} G_i(1) = ∏_{i=1}^{n} (f(e_i) + p * g(e_i)),
而
∏_{i=1}^{n} G_i(-1) = ∏_{i=1}^{n} (f(e_i) - p * g(e_i))。
如果我们把同一质数 p 在所有 a_i 作“归类”,记对于给定 p 有 c_e 个 a_i 使得 e_i = e(只考虑 e ≥ 1,因为 e = 0 贡献 1),那么
X = ∏_{e ≥ 1} (f(e) + p * g(e))^c_e,
Y = ∏_{e ≥ 1} (f(e) - p * g(e))^c_e。
最后对于质数 p 的贡献为
S_p = (X + Y) / 2。
由于各质数相互独立,最终答案
S = ∏_p S_p mod 10^9 + 7。
在模 M = 10^9+7 意义下构造一个二次扩域,令每个数表示为 (x + y * p)(注意这里每质数 p 固定,我们把它当作常数)。在该域中定义加法和乘法:
加法:
(x_1, y_1) + (x_2, y_2) = (x_1 + x_2, y_1 + y_2)。
乘法:
(x_1, y_1) * (x_2, y_2) = (x_1 * x_2 + y_1 * y_2 * p, x_1 * y_2 + x_2 * y_1)。
经过所有计算,S_p 理论上是“实数”(即扩域中第二项为 0),我们只取其第一项 mod M。
---------------------------------------------------------------------------------------------------------------------------------
我们先线性筛求最小质因数 spf
对每个 a_i 进行质因数分解:使用 spf 数组分解 a_i,得到所有质因数 p 及其指数 e。 对于每个 p,统计其 e 在全局数组 freq 中出现次数。
然后扩域运算并求多项式系数,进行组合求和
const int MOD = 1000000007;
const int maxn = 1000000;
vector<int> spf(maxn+1);
void sieve() {
for (int i = 2; i <= maxn; i++) spf[i] = 0;
for (int i = 2; i <= maxn; i++) {
if (!spf[i]) {
spf[i] = i;
if ((LL)i*i <= maxn) {
for (int j = i*i; j <= maxn; j += i)
if(!spf[j]) spf[j] = i;
}
}
}
}
struct Ext {
LL a, b;
};
LL CURR_P;
Ext ext_add(const Ext &X, const Ext &Y) {
return { (X.a + Y.a) % MOD, (X.b + Y.b) % MOD };
}
Ext ext_mul(const Ext &X, const Ext &Y) {
return { (X.a * Y.a % MOD + (X.b * Y.b % MOD) * (CURR_P % MOD) % MOD) % MOD,
(X.a * Y.b + X.b * Y.a) % MOD };
}
Ext ext_pow(Ext base, LL exp) {
Ext res = {1, 0};
while(exp > 0){
if(exp & 1) res = ext_mul(res, base);
base = ext_mul(base, base);
exp /= 2;
}
return res;
}
LL modinv(LL x, LL mod=MOD) {
LL res = 1, p = mod-2;
while(p){
if(p & 1) res = res * x % mod;
x = x * x % mod;
p /= 2;
}
return res;
}
int32_t main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
// Code Start Here
sieve();
int n;
cin >> n;
vector<int> a(n);
for (int i=0; i<n; i++){
cin >> a[i];
}
unordered_map<int, unordered_map<int, LL> > freq;
for (int i = 0; i < n; i++){
int x = a[i];
while(x > 1){
int p = spf[x];
int cnt = 0;
while(x % p == 0) { cnt++; x /= p; }
freq[p][cnt]++;
}
}
LL ans = 1;
LL inv2 = modinv(2);
for(auto &entry : freq){
int p = entry.first;
CURR_P = p;
auto &mp = entry.second;
int maxE = 0;
for(auto &kv : mp) {
maxE = max(maxE, kv.first);
}
vector<LL> F(maxE+1, 0), G(maxE+1, 0);
for (int e = 1; e <= maxE; e++){
int m1 = e / 2;
LL sumf = 0, cur = 1;
for (int j = 0; j <= m1; j++){
sumf = (sumf + cur) % MOD;
cur = (cur * p) % MOD;
}
F[e] = sumf;
int m2 = (e - 1) / 2;
LL sumg = 0; cur = 1;
for (int j = 0; j <= m2; j++){
sumg = (sumg + cur) % MOD;
cur = (cur * p) % MOD;
}
G[e] = sumg;
}
Ext X = {1, 0}, Y = {1, 0};
for(auto &kv : mp){
int e = kv.first;
LL cnt = kv.second;
Ext curVal = { F[e] % MOD, G[e] % MOD };
Ext curVal_conj = { F[e] % MOD, (MOD - G[e]) % MOD }; // 共轭: f - sqrt(p)*g
Ext t1 = ext_pow(curVal, cnt);
Ext t2 = ext_pow(curVal_conj, cnt);
X = ext_mul(X, t1);
Y = ext_mul(Y, t2);
}
Ext sumXY = ext_add(X, Y);
LL Sp = sumXY.a % MOD;
Sp = (Sp * inv2) % MOD;
ans = (ans * Sp) % MOD;
}
cout << ans % MOD << "\n";
return 0;
}
题意:
一共有n个人,每个人每个学期都有智育、德育、体育三项得 分,每个学期会根据这三个得分按照一定规则评选奖学金,在评 完两个学期的奖学金之后会根据大家的奖学金获得情况,综测总 分和智育总分决定省政府奖学金的得主。现在告诉你所有人这两 个学期的成绩,你可以花费p代价提升小凯第一学期智育分1 分,q代价提升第二学期智育分1分,智育分上限100分,问小 凯花费最少多少的代价能够获得省政府奖学金
思路:一个超级无敌大模拟。分开处理两个学期的得奖情况,O(100∗nlogn)处理好第一学期的,然后存在vector里,第二学期直接在第一学期基础上做
网上有代码,这个码有点大,偷个懒省略一下

1586

被折叠的 条评论
为什么被折叠?



