Educational Codeforces Round 66小结

前言:

发现这几场都有一个特点:问题有趣且经典,也有一定难度,我比较喜欢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 1k.使得 ∑ i = 1 n a i ∗ i d ( a i ) \sum_{i=1}^{n}a_i*id(a_i) i=1naiid(ai)最大.

n ≤ 1 e 5 n \leq 1e5 n1e5

题目思路:

竟然感觉这题目挺水的。还是换一种统计方式。你想一想 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 k1个位置,使得它们的后缀和之和最大。自然就是排序取前 k − 1 k-1 k1大。

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,Ri5e5

题目思路:

这其实是一个经典问题的升级多询问版本。而且要注意到区间的范围也很小。

对于一个询问,我们可以贪心的去做。

但是这里我们考虑对于每一个点 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(i1,j1) d p ( d p ( i − 1 , j − 1 ) , j − 1 ) dp(dp(i-1,j-1),j-1) dp(dp(i1,j1),j1)。得到最优结果。

然后询问的时候,也是不断的往后跳。复杂度可以证明为 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

见我下一篇博客

猜你喜欢

转载自blog.csdn.net/qq_35577488/article/details/114004975
今日推荐