• 20180824Noip模拟赛10分总结


    嗯,总之,是我太傻了。

    我真傻,真的,我单知道最小生成树,却不知道还有最大生成树

    T1

    最大生成树....

    累加每一个环内,最大生成树的边权,(对环求最大生成树,则必然剩下一个边权最小的边(因为是求生成树,所以这个边肯定不会被算上))

    然后因为对于不同联通块,跑最大生成树,彼此之间依旧无法有想连接的边,所以对于森林跑最大生成树是没有问题的

    最后所有边的边权和 减去 所有联通块的最大生成树的边权和 即可得到答案

    最小生成树性质之一:最大边权最小

    最大生成树性质之一:最小边权最大

    最后是吐槽:我写了4kb的dfs,疯狂地dfs,使用各种奇奇怪怪的操作,并且计算的复杂度是允许的!最后好不容易调过了样例

    最后因为数组开的太大,直接MLE,连正确性都不知道....

    AC代码如下:

     1 #include<bits/stdc++.h>
     2 #define uint unsigned int
     3 using namespace std;
     4 const int maxn = 10086;
     5 const int maxm = 50010;
     6 struct shiki {
     7     int x, y; 
     8     double val;
     9 }e[maxm << 1];
    10 struct enkidu {
    11     int x, y;
    12 }a[maxn];
    13 int lin[maxn], len = 0;
    14 int fa[maxn];
    15 double num, need;
    16 int n, m;
    17 
    18 inline int read() {
    19     int x = 0, y = 1;
    20     char ch = getchar();
    21     while(!isdigit(ch)) {
    22         if(ch == '-') y =-1;
    23         ch = getchar();
    24     }
    25     while(isdigit(ch)) {
    26         x = (x << 1) + (x << 3) + ch - '0';
    27         ch = getchar();
    28     }
    29     return x * y;
    30 }
    31 
    32 inline bool cmp(shiki x, shiki y) {
    33 return x.val > y.val;}
    34 
    35 inline double dis_val(int x, int y) {
    36     int x1 = a[x].x, y1 = a[x].y, x2 = a[y].x, y2 = a[y].y;
    37     return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
    38 }
    39 
    40 int getfather(int x) {
    41     if(x == fa[x]) return x;
    42     return fa[x] = getfather(fa[x]);
    43 }
    44 
    45 int main() {
    46 //    freopen("plan.in", "r", stdin);
    47 //    freopen("plan.out", "w", stdout);
    48     n = read(), m = read();
    49     for(register uint i = 1; i <= n; ++i)
    50         a[i].x = read(), a[i].y = read();
    51     for(register uint i = 1; i <= m; ++i) {
    52         e[i].x = read(), e[i].y = read();
    53         e[i].val = dis_val(e[i].x, e[i].y);
    54     }
    55     for(register uint i = 1; i <= n; ++i) fa[i] = i;
    56     sort(e + 1, e + m + 1, cmp);
    57     for(register uint i = 1; i <= m; ++i) {
    58         int u = getfather(e[i].x);
    59         int v = getfather(e[i].y);
    60         num += sqrt(e[i].val);
    61         if(u == v) continue;    
    62         fa[u] = v;
    63         need += sqrt(e[i].val);
    64     }
    65     printf("%0.9lf", num - need);
    66 //    fclose(stdin);
    67 //    fclose(stdout);
    68     return 0;
    69 }

    T2

    我T1为了完成sb的4kb的超暴力搜索,花费了差不多2个小时的时间,然后看到这道题后,我一眼以为是一个博弈论...

    然后我又想了想,觉得自己的题意好像出锅了....

    然后就按照贪心思想完成了一个dfs,最后贪心顺利骗到10分...

    Dp
    题意:
    最优策略指:差值最大

    因为我们在某个位置选或是不选由[i+1, i+m]中的状态推导来的,也就是说,我们要保证下一个人取得是最优策略。

    但是我们正序进行的话,我们无法保证当前状态是最优策略,所以我们倒序进行

    划分阶段:
    以进行每个点i为阶段
    f[i]表示,在当前回合,选择数ai时,所能得到的最大得分
    添加状态

    正常操作:
    f[i][0]表示到第i个数时,该棋子为大魔王选时,你的得分减去大魔王的得分
    f[i][1]表示到第i个数时,该棋子为你选时,你的得分减去大魔王的得分
    f[i][0] = max{f[k][1]} - a[i]
    f[i][1] = min{f[k][0]} + a[i]
    也就是说要维护f[k][1]和f[k][0]在[i-m, i-1]的单调性

    倒序与第一题一样

    优化1:空间优化
    假定第ai个数必须取,f[i]表示若选择一定选择第ai个数,当前的人和对方的最大差值
    因为每个人都取最优策略,所以选择第ai个数我们能够得到的分数是
    f[i] = ai - max{f[j]}(j ∈ [i+1, i+m])
    可得方程f[i] = ai - max{f[j]}(j ∈ [i+1, i+m])

    因为f[j]是对方的最大差值,我们选择了a[i],则我们要计算自己的得分,就要用a[i] - max{f[j]}

    优化2:时间优化:
    (1)单调队列维护单调性:好写,代码量小
    (2)线段树取区间最大值,正常操作,显然

     1 #include<bits/stdc++.h>
     2 #define uint unsigned int
     3 #define ll long long
     4 using namespace std;
     5 const int maxn = 100086;
     6 int q[maxn];
     7 int f[maxn];
     8 int n, m;
     9 int a[maxn];
    10 int l = 1, r = 0;
    11 int ans = -1999999999;
    12 
    13 inline int read() {
    14     int x = 0, y = 1;
    15     char ch = getchar();
    16     while(!isdigit(ch)) {
    17         if(ch == '-') y = -1;
    18         ch = getchar();
    19     }
    20     while(isdigit(ch)) {
    21         x = (x << 1) + (x << 3) + ch - '0';
    22         ch = getchar();
    23     }
    24     return x * y;
    25 }
    26 
    27 int main() {
    28 //    freopen("game.in", "r", stdin);
    29 //    freopen("game.out", "w", stdout);
    30     n = read(), m = read();
    31     for(register uint i = 1; i <= n; ++i) a[i] = read();
    32     f[n] = a[n];
    33     q[++r] = n;
    34     for(register uint i = n - 1; i >= 1; --i) {
    35         while(l <= r && q[l] > i + m) l++;
    36         f[i] = a[i] - f[q[l]];
    37         while(l <= r && f[q[r]] < f[i]) r--;
    38         q[++r] = i;
    39     }
    40     for(register uint i = 1; i <= m; ++i) 
    41         ans = max(ans, f[i]);
    42     cout << ans << '
    ' << -ans << '
    ';
    43 //    fclose(stdin);
    44 //    fclose(stdout);
    45     return 0;
    46 }

    T3

     不得不说,样例就是sb,我最初以为是只能从根节点出发

    然后我就写了个树Dp的暴力,然后就爆0了

    后来才知道,是求的直径.....

    暴力思路:

    对于每一次询问,都手动封点,求树的直径

    能拿50%的分

    正解思路:不会,回来补吧....

  • 相关阅读:
    初始MyBatis
    h5调用相机相册
    canvas详解
    js闭包
    Vue和React对比篇
    js造成内存泄漏的几种情况
    js合并对象
    git常用命令小结
    如何隐藏overflow: scroll的滚动条
    js数组sort排序方法的算法
  • 原文地址:https://www.cnblogs.com/ywjblog/p/9532006.html
Copyright © 2020-2023  润新知