前言:
发现这几场都有一个特点:问题有趣且经典,也有一定难度,我比较喜欢hh
C.Electrification
题目思路:
找规律:
k = 0 k=0 k=0,一定在某个点上
k = 1 k=1 k=1,一定某两个相邻点之间的最远距离.
k = x k=x k=x,一定在某 k + 1 k+1 k+1个相邻点之间的最远距离。
所以暴力考虑每一个连续 k k k个相邻点的两端点距离的中点值即可。
D.Array Splitting
题目大意:
给你一个数组,让你划分成 k k k个子数组,每个子数组有它的编号,从左到右 1 到 k 1到k 1到k.使得 ∑ i = 1 n a i ∗ i d ( a i ) \sum_{i=1}^{n}a_i*id(a_i) ∑i=1nai∗id(ai)最大.
n ≤ 1 e 5 n \leq 1e5 n≤1e5
题目思路:
竟然感觉这题目挺水的。还是换一种统计方式。你想一想 k = 1 k=1 k=1转移到 k = 2 k=2 k=2.再转移到 k = 3 k=3 k=3.值怎么变化的大概就清楚了。
根据上面的累和式,我们发现可以将其看作是在区间 [ 2 , n ] [2,n] [2,n]上选择 k − 1 k-1 k−1个位置,使得它们的后缀和之和最大。自然就是排序取前 k − 1 k-1 k−1大。
E .Minimal Segment Cover
题目大意:
给你 n n n个线段,给你 m m m次独立的询问,每次询问最少拿多少个线段能够完整覆盖 [ L i , R i ] [L_i,R_i] [Li,Ri]
n , m , L i , R i ≤ 5 e 5 n,m,L_i,R_i \leq 5e5 n,m,Li,Ri≤5e5
题目思路:
这其实是一个经典问题的升级多询问版本。而且要注意到区间的范围也很小。
对于一个询问,我们可以贪心的去做。
但是这里我们考虑对于每一个点 i i i,求出使用 j j j个线段之后能够到达的最远的地方. O ( n m ) O(nm) O(nm)无法接受。利用倍增优化这个过程即可

对于 d p ( i , j ) dp(i,j) dp(i,j)我们合并两个区间 d p ( i − 1 , j − 1 ) dp(i-1,j-1) dp(i−1,j−1)和 d p ( d p ( i − 1 , j − 1 ) , j − 1 ) dp(dp(i-1,j-1),j-1) dp(dp(i−1,j−1),j−1)。得到最优结果。
然后询问的时候,也是不断的往后跳。复杂度可以证明为 O ( l o g n ) O(logn) O(logn).整体就是 O ( n l o g n ) O(nlogn) O(nlogn)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vl vector<ll>
const int maxn = 5e5 + 5;
const int mod = 1e9 + 7;
int dp[maxn][20];/*dp[i][j] 代表第i个位置,使用2^j个线段达到的最远位置*/
int main()
{
ios::sync_with_stdio(false);
int n , m; cin >> n >> m;
for (int i = 1 ; i <= n ; i++){
int x , y; cin >> x >> y;
dp[x][0] = max(dp[x][0] , y);
}
for (int i = 0 ; i < maxn ; i++){
dp[i][0] = max(dp[i][0] , dp[i - 1][0]);
if (dp[i][0] <= i) dp[i][0] = 0;
}
for (int j = 1 ; j < 20 ; j++){
for (int i = 0 ; i < maxn ; i++){
if (!dp[i][j - 1]) continue;
if (!dp[dp[i][j - 1]][j - 1]) continue;
dp[i][j] = dp[dp[i][j - 1]][j - 1];
}
}
for (int i = 1 ; i <= m ; i++){
int x , y; cin >> x >> y;
int pos = x , res = 0;
for (int i = 19 ; i >= 0 ; i--){
if (dp[pos][i] == 0) continue;
if (dp[pos][i] >= y) continue;
pos = dp[pos][i];
res += (1 << i);
}
if (dp[pos][0] >= y) cout << res + 1 << endl;
else cout << -1 << endl;
}
return 0;
}
F. The Number of Subpermutations
见我下一篇博客