\(Day_1T_1\) 铺设道路 (Link

现在你有一个序列,每一个\(i\)有一个深度\(Deep[i]\),现在你可以选择任意的区间,将整个区间的\(Deep\)都减少\(1\)。但前提是这个区间不能有任意一个点的\(Deep\)大于等于\(0\)。求进行多少次操作可以将整个序列的所有\(Deep\)置为\(0\)。

这个题的数据范围比较的大,\(1 ≤ n ≤ 100000,0 ≤ d_i ≤ 10000\)。观察发现时间复杂度应该限制在\(O(N)\)或者\(O(NlogN)\)以内,当然如果可以\(O(logN)\)更好,但这个好像是无法实现的。
\(O(NlogN)\):这个是笔者在考场上想出来的,五分钟敲完发现秒了大样例就走了。用的方法是一个二分。我们发现你选择的这个区间的限制不在于\(Deep[i]_{Max}\),而在于\(Deep[i]_{Min}\)。什么意思呢。比如这个区间\(\{4~ 3~ 2~ 5~ 3~ 5 \}\)。
我们肯定首先要整体切两次。因为整个区间内的最小值为\(2\),然后区间变为\(\{2~ 1~ 0~ 3~ 1~ 3 \}\)出现了\(0\),我们再考虑做其他的事情。
于是我们发现了算法流程:
\(1.\)对于区间\([L, R]\),寻找到区间最小的点的位置\(Pos\)
\(2.\)\(Ans += Deep[Pos]\)
\(3.\)二分\([L, Pos - 1]\), \([Pos + 1, R]\)。
遍历\([L, R]\)总时间复杂度是\(O(N)\),二分的时间复杂度是\(O(logN)\),总时间复杂度\(O(NlogN)\)。也算是卡着过去了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std ;

typedef long long LL ;
const int MAXN = 100010 ;
const int Inf = 0x7fffffff ;
LL N, Data[MAXN], Tag[MAXN], Max[MAXN][23], Ans ;

inline LL Read() {
    LL X = 0, F = 1 ; char ch = getchar() ;
    while (ch > '9' || ch < '0') F = (ch == '-') ? - 1 : 1, ch = getchar() ;
    while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
    return X * F ;
}

inline void Erfen(int L, int R, int T) {
    if (L == R) {
        Ans += Data[L] - T ;
        return ;
    }   LL Min = Inf, Pos = 0 ;
    for (int i = L ; i <= R ; i ++)
        Pos = Min > Data[i] ? i : Pos, Min = Min > Data[i] ? Data[i] : Min ;
    Min -= T ; Ans += Min ;
    if(Pos > L) Erfen(L, Pos - 1, T + Min) ;
    if(Pos < R) Erfen(Pos + 1 , R, T + Min) ;
    return ;
}

int main() {
    N = Read() ;
    for (int i  = 1 ; i <= N ; i ++) Data[i] = Read() ;
    int L = 1, R = N ;  LL Min = Inf, Pos = 0 ;
    for (int i = 1 ; i <= N ; i ++)
        Pos = Min > Data[i] ? i : Pos, Min = Min > Data[i] ? Data[i] : Min ;
    Ans += Min ;
    if (Pos > 1) Erfen(1, Pos - 1, Min) ;
    if (Pos < N) Erfen(Pos + 1, N, Min) ;
    printf("%lld", Ans) ;
    fclose(stdin) ; fclose(stdout) ;
    return 0 ;
}

\(O(N)\):如果你愿意在考场上多花一点时间思考一下以保证\(AC\)的话,你可以发现这其实就是一个贪心,你发现对于两个相邻的数\(Deep[i]\)和\(Deep[i + 1]\),如果\(Deep[i] > Deep[i + 1]\),那么我们肯定会要把两个坑都填上,这时如果我们选择了区间[i, i + 1],你发现根本就不需要加上\(Deep[i + 1]\)所要耗费的次数,因为他一定会被\(i\)点顺带着填掉。那么我们发现贪心的规律:对于每一个\(i\), 如果\(Deep[i] > Deep[i + 1]\)(当然也可以是小于,没有分别),\(Ans += Deep[i] - Deep[i + 1]\)。
复杂度\(O(N)\),没有什么问题;

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std ;

typedef long long LL ;
const int MAXN = 100010 ;
const int Inf = 0x7fffffff ;
LL N, Deep[MAXN], Ans ;

inline LL Read() {
    LL X = 0, F = 1 ; char ch = getchar() ;
    while (ch > '9' || ch < '0') F = (ch == '-') ? - 1 : 1, ch = getchar() ;
    while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
    return X * F ;
}

int main() {
    N = Read() ;
    for (int i = 1 ; i <= N ; i ++) {
        Deep[i] = Read() ;
        Ans += (Deep[i] > Deep[i - 1]) ? (Deep[i] - Deep[i - 1]) : 0 ;
    }   printf("%lld", Ans) ; return 0 ;
}

\(Day_1T_2\) 货币系统(Link

现在你有一个叫做货币系统的东西,里面包括\(N\)种货币面值和面值的集合A。我们把这种货币集合叫做(N, A)。我们定义两个货币集合相等,当且仅当对于每一个数\(X\),它要么都能被两个系统表示,要么都不能。求与(N, A)相等的货币系统的最小的\(N\)。

实际上这到题考的就是一个完全背包。我们分析样例
\(4\)
\(3~ 19~ 10~ 6\)
可以发现,这里面的\(6\)可以被两个\(3\)表示,因此它无用,\(19\)可以被一个\(10\)和\(3\)个\(3\)表示,因此它也无用。所以得出答案就是2种。
于是我们发现,如果有一种面值是可以被其余的面值表示出来的,那么它就可以被筛掉。于是我们找到了算法流程:
\(1.\)从大到小排序。并且我们知道最小的面值一定要选。
\(2.\)对于每一个\(Data[i]\),如果它已经被标记,那么\(continue\)。
\(3.\)计数器\(Ans++\),标记\(F[Data[i]] = 1\)
\(4.\)从当前的\(Data[i]\)开始循环足够多的数,如果\(F[j - Data[i]] = 1\),那么代表加上\(Data[i]\)之后还是可以被筛掉,那么\(F[j] = 1\)。
\(Over\),时间复杂度为\(O(25000TN)\)算一算发现没有超时。完美。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
const int MAXN = 10010 ;
const int MAXM = 25000 ;

int N, M, Data[MAXN], T, F[MAXM], Total ;

inline int Read() {
    int X = 0, F = 1 ; char ch = getchar() ;
    while (ch > '9' || ch < '0') F = (ch == '-' ? - 1 : 1), ch = getchar() ;
    while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
    return X * F ;
}

inline bool CMP(int X, int Y) { return X < Y ; }

int main() {
    T = Read() ; while (T --) {
        N = Read() ; Total = 0 ;
        memset(Data, 0, sizeof(Data)) ;
        memset(F, 0, sizeof(F)) ;
        for (int i = 1 ; i <= N ; i ++)
            Data[i] = Read(), M = max(M, Data[i]) ;
        sort(Data + 1 , Data + N + 1, CMP) ;
        for (int i = 1 ; i <= N ; i ++) {
            if (F[Data[i]]) continue ;
            Total ++ ; F[Data[i]] = 1 ;
            for (int j = Data[i] ; j <= M ; j ++)
                if (F[j - Data[i]]) F[j] = 1 ;
        }   printf("%d\n", Total) ;
    }   return 0 ;
}

\(Day_2T_1\) 旅行(Link

你有一张\(N\)点\(M\)边的无向图,现在你可以从任意一个点出发,或者走向与它链接的没有走过的点,或者沿着d第一次访问该点的时候经过的城市退到上一个点。必须走完所有的点,要求输出字典序最小的方案。

\(Subtask_1 ~ M = N - 1\)

这显然是一个树,我们显然要从\(1\)号节点出发,然后每一次选择与他相连的子节点中最小的点,那么我们可以对每一个点连接的点进行一个从小到大的排序,然后进行一遍\(Dfs\)就可以了。思考难度接近\(0\),但是占了\(60\)的高分,这大概也就是为什么它的难度排在了\(Day_2T_1\)。

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
const int MAXN = 5050 ;
const int MAXM = 5050 ;

int N, M, Tot, H[MAXN], SF, ST, Ans[MAXN], Cnt ;
int E[MAXN][MAXN], Edge[MAXN][2], L[MAXN] ;
bool Vis[MAXN] ;

inline int Read() {
    int X = 0, F = 1 ; char ch = getchar() ;
    while (ch > '9' || ch < '0') F = (ch == '-' ? - 1 : 1), ch = getchar() ;
    while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
    if (ch == '-') return -X;
    return X;
}

inline void Doit(int Now, int Fa) {
    printf("%d ", Now) ;
    sort(E[Now] + 1, E[Now] + H[Now] + 1) ;
    for (int i = 1 ; i <= H[Now] ; i ++)
        if (E[Now][i] != Fa) Doit(E[Now][i], Now) ;
}

int main() {
    N = Read() ; M = Read() ;
    for (int i = 1 ; i <= M ; i ++) {
        int X = Read(),  Y = Read() ;
        E[X][++ H[X]] = Y ; E[Y][++ H[Y]] = X ;
        Edge[i][0] = X ; Edge[i][1] = Y ;
    }
    if (M == N - 1) Doit(1, 0) ;
    return 0 ;
}

\(Subtask_2 ~ M = N\)

这个就有一点难度了,起码不是那种让人一眼瞧出来的那种。我们发现这种图就是比一棵树多了一条边,那么我们知道它肯定会构成一个环并且仅会构成一个环,所以我们知道这是个基环树。

题目要求的是走完所有的点,则只可能走\(N - 1\)条边,也就是时候不论怎么走都会剩下一条边没走,那么我们就可以采取暴力手段,每次选取一条边把他删掉,确切的来说是记录下来,然后\(Dfs\)的时候如果碰到这条边就不走,然后对于每次的方案取最优即可。

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long LL ;
const int MAXN = 5050 ;
const int MAXM = 5050 ;

int N, M, Tot, H[MAXN], SF, ST, Ans[MAXN], Cnt ;
int E[MAXN][MAXN], Edge[MAXN][2], L[MAXN] ;
bool Vis[MAXN] ;

inline int Read() {
    int X = 0, F = 1 ; char ch = getchar() ;
    while (ch > '9' || ch < '0') F = (ch == '-' ? - 1 : 1), ch = getchar() ;
    while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
    if (ch == '-') return -X;
    return X;
}

inline void Doit(int Now, int Fa) {
    printf("%d ", Now) ;
    sort(E[Now] + 1, E[Now] + H[Now] + 1) ;
    for (int i = 1 ; i <= H[Now] ; i ++)
        if (E[Now][i] != Fa) Doit(E[Now][i], Now) ;
}

inline void Dfs(int Now, int Fa) {
    L[++ Cnt] = Now ; Vis[Now] = 1 ;
    for (int i = 1 ; i <= H[Now] ; i ++) {
        if(! Vis[E[Now][i]] && ! ((Now == SF && E[Now][i] == ST) ||(Now == ST && E[Now][i] == SF)))
            Dfs(E[Now][i], Now) ;
    }
}

inline bool Judge() {
    for (int i = 1 ; i <= N ; i ++)
        if (Ans[i] != L[i]) return Ans[i] > L[i] ;
    return false ;
}

inline void WORK() {
    memset(Ans, 127, sizeof(Ans)) ; memset(Vis, 0, sizeof(Vis)) ;
    for (int i = 1 ; i <= N ; i ++) sort(E[i] + 1, E[i] + H[i] +1) ;
    //把每一条边连接的点都排序 

    for (int i = 1 ; i <= M ; i ++) { Cnt = 0 ;
        memset(L, 0, sizeof(L)) ; memset(Vis, 0, sizeof(Vis)) ;
        SF = Edge[i][0], ST = Edge[i][1] ;
        Dfs(1, 0) ;
        if (Judge() && Cnt == N)
            for (int i = 1 ; i <= N ; i ++)
                Ans[i] = L[i] ;
    }
    for (int i = 1 ; i <= N ; i ++) printf("%d ", Ans[i]) ;
}

int main() {
    N = Read() ; M = Read() ;
    for (int i = 1 ; i <= M ; i ++) {
        int X = Read(),  Y = Read() ;
        E[X][++ H[X]] = Y ; E[Y][++ H[Y]] = X ;
        Edge[i][0] = X ; Edge[i][1] = Y ;
    }
    if (M == N - 1) Doit(1, 0) ;
    else WORK() ;     return 0 ;
}

其实仔细想一想这道题也并不是特别的难,如果只停留在暴力删边的方法上的话。这里直接爆删是没法通过所有的测试点的,但是\(88\)分的成绩也不错了,加上在\(Dfs\)的过程中的一些最优性剪枝和玄学优化的话是可以卡过去的。然而还有一种十分玄的做法是边删边维护以做到\(O(N)\),就不再说了(懒

以及可以扩展到不限制\(M\)的情况下在仙人掌图上做,可是我不会~~~

NOIP2018(更新中)的更多相关文章

  1. 在UPDATE中更新TOP条数据以及UPDATE更新中使用ORDER BY

    正常查询语句中TOP的运用: SELECT TOP 1000 * FROM MP_MemberGrade   随意更新一张表中满足条件的前N条数据: UPDATE TOP (1) MP_Member ...

  2. git常用命令(持续更新中)

    git常用命令(持续更新中) 本地仓库操作git int                                 初始化本地仓库git add .                       ...

  3. Atom使用记录(持续更新中)

    部分内容取自:http://www.jianshu.com/p/dd97cbb3c22d,我自己也在使用,持续更新中 Atom安装插件在窗口中File---Setting---install 在里面进 ...

  4. Pig基础学习【持续更新中】

    *本文参考了Pig官方文档以及已有的一些博客,并加上了自己的一些知识性的理解.目前正在持续更新中.* Pig作为一种处理大规模数据的高级查询语言,底层是转换成MapReduce实现的,可以作为MapR ...

  5. Pig语言基础-【持续更新中】

      ***本文参考了Pig官方文档以及已有的一些博客,并加上了自己的一些知识性的理解.目前正在持续更新中.***   Pig作为一种处理大规模数据的高级查询语言,底层是转换成MapReduce实现的, ...

  6. java视频教程 Java自学视频整理(持续更新中...)

    视频教程,马士兵java视频教程,java视频 1.Java基础视频 <张孝祥JAVA视频教程>完整版[RMVB](东西网) 历经5年锤炼(史上最适合初学者入门的Java基础视频)(传智播 ...

  7. 微软承诺将在今年的 Visual C++ 更新中加入 Clang 编译器

    微软最近发布将在2015年11月 Visual C++ 更新中加入 Clang 编译器 ,Clang 开源编译器以相比GCC更快的编译速度和更优的错误提示著称. Clang关于C,C++,及Objec ...

  8. 系列文章:老项目的#iPhone6与iPhone6Plus适配#(持续更新中,更新日期2014年10月12日 星期日 )

    本文永久地址为http://www.cnblogs.com/ChenYilong/p/4020399.html ,转载请注明出处. ********************************** ...

  9. 免费api大全(更新中)

    免费api大全(更新中) API大全  http://www.apidq.com/    (这个碉堡了) 天气接口 气象局接口 完整数据:http://m.weather.com.cn/data/10 ...

  10. IIC,RS485,RS232各种协议手册更新中

     RS485使用手册与指南.pdf  RS232协议标准详解.pdf IIC通信协议.pdf 链接:http://pan.baidu.com/s/1ccBtmA 密码:mwj6 IIC,RS485,R ...

随机推荐

  1. json转化的时候如何忽略某些属性字段值

    一.有时候在将对象或list对象转化为json的时候,我们可能不需要所有的属性值,这就需要我们去过滤掉这些属性了 我下面说两种比较流行的json包如何来忽略某些属性值 二. 使用jaskson包 1. ...

  2. 编写DBCP连接池

    #配置数据库数据源package com.itang.utils; import java.io.InputStream; import java.sql.Connection; import jav ...

  3. django基础一:web、wsgi、mvc、mtv

    一.web框架 web框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以快速开发特定的系统.他山之石,可以攻玉.python的所有web框架,都是对so ...

  4. hdu 4003 Find Metal Mineral 树形dp ,*****

    Find Metal Mineral Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Other ...

  5. Android加载大图片实例详解

    摘要:在Android下采用ARGB表示颜色,每个像素占四个字节.其加载图片申请空间时与图片的实际大小没有关系,与像素有关系.

  6. 获取页面z-index最大值

    getMaxZIndex = function () { var maxZ = Math.max.apply(null, $.map($('body *'), function(e,n) { if ( ...

  7. cf1043E. Mysterious Crime(二分 前缀和)

    题意 题目链接 Sol 考场上做完前四题的时候大概还剩半个小时吧,那时候已经困的不行了. 看了看E发现好像很可做?? 又仔细看了几眼发现这不是sb题么... 先考虑两个人,假设贡献分别为\((x, y ...

  8. CSS背景相关属性

    CSS样式可以精确控制HTML元素的背景.边框的样式和外观,也可以精确控制边框的线型和形状.其中,背景相关属性可以用于控制背景色.背景图片等属性.在控制背景图片的同时还可以控制背景图片的排列方式. 常 ...

  9. Linux系统搭建GitLab---阿里云Centos7搭建Gitlab踩坑

    一.简介 GitLab,是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目安装. 它拥有与GitHub类似的功能,能 ...

  10. 05_zookeeper的ACL

    [ACL概述] ACL:access control Lists,权限控制. * 针对节点可以设置相关的读写等权限,目的是为了保障数据安全性. * 权限permissions可以指定不同的权限范围以及 ...