zoukankan      html  css  js  c++  java
  • noip2010 真题练习 2017.2.18


      第一题比较简单,用exist数组判断是否在循环队列中,就可实现线性算法。

    Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cctype>
     4 #include<cstring>
     5 #include<cstdlib>
     6 #include<fstream>
     7 #include<sstream>
     8 #include<algorithm>
     9 #include<map>
    10 #include<set>
    11 #include<queue>
    12 #include<vector>
    13 #include<stack>
    14 using namespace std;
    15 typedef bool boolean;
    16 #define INF 0xfffffff
    17 #define smin(a, b) a = min(a, b)
    18 #define smax(a, b) a = max(a, b)
    19 template<typename T>
    20 inline void readInteger(T& u){
    21     char x;
    22     int aFlag = 1;
    23     while(!isdigit((x = getchar())) && x != '-');
    24     if(x == '-'){
    25         x = getchar();
    26         aFlag = -1;
    27     }
    28     for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0');
    29     ungetc(x, stdin);
    30     u *= aFlag;
    31 }
    32 
    33 int n, m;
    34 int top;
    35 int *s;
    36 boolean exist[1002];
    37 
    38 inline void s_push(int* sta, int x) {
    39     exist[sta[top] + 1] = false;
    40     sta[top] = x;
    41     exist[x + 1] = true;
    42     if(top == m - 1)    top = 0;
    43     else top = top + 1;
    44 }
    45 
    46 int res = 0;
    47 inline void solve() {
    48     readInteger(m);
    49     readInteger(n);
    50     s = new int[(const int)(m + 1)];
    51     memset(s, -1, sizeof(int) * (m + 1));
    52     top = 0;
    53     for(int i = 1, a; i <= n; i++) {
    54         readInteger(a);
    55         if(!exist[a + 1]) {
    56             res++;
    57             s_push(s, a);
    58         }
    59     }
    60     printf("%d", res);
    61 }
    62 
    63 int main() {
    64     freopen("translate.in", "r", stdin);
    65     freopen("translate.out", "w", stdout);
    66     solve();
    67     return 0;
    68 }


      因为当卡牌的选择数是固定的情况下,跳的长度也就知道了,于是就可以用四种卡牌来做状态,得到了dp方程:

      为了防止过多的无用的状态,所以就用记忆化搜索(其实直接4个for也没什么问题)

    Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cctype>
     4 #include<cstring>
     5 #include<cstdlib>
     6 #include<fstream>
     7 #include<sstream>
     8 #include<algorithm>
     9 #include<map>
    10 #include<set>
    11 #include<queue>
    12 #include<vector>
    13 #include<stack>
    14 using namespace std;
    15 typedef bool boolean;
    16 #define INF 0xfffffff
    17 #define smin(a, b) a = min(a, b)
    18 #define smax(a, b) a = max(a, b)
    19 template<typename T>
    20 inline void readInteger(T& u){
    21     char x;
    22     int aFlag = 1;
    23     while(!isdigit((x = getchar())) && x != '-');
    24     if(x == '-'){
    25         x = getchar();
    26         aFlag = -1;
    27     }
    28     for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0');
    29     ungetc(x, stdin);
    30     u *= aFlag;
    31 }
    32 
    33 int n, m;
    34 int counter[4];
    35 int f[41][41][41][41];
    36 boolean vis[41][41][41][41];
    37 int *val;
    38 
    39 inline void init() {
    40     readInteger(n);
    41     readInteger(m);
    42     memset(counter, 0, sizeof(counter));
    43     memset(f, 0, sizeof(f));
    44     memset(vis, false, sizeof(vis));
    45     val = new int[(const int)(n + 1)];
    46     for(int i = 1; i <= n; i++)        readInteger(val[i]);
    47     for(int i = 1, a; i <= m; i++) {
    48         readInteger(a);
    49         counter[a - 1]++;
    50     }
    51     f[0][0][0][0] = val[1];
    52     vis[0][0][0][0] = true;
    53 }
    54 
    55 int dfs(int a, int b, int c, int d) {
    56     if(vis[a][b][c][d])    return f[a][b][c][d];
    57     vis[a][b][c][d] = true;
    58     int pos = a * 1 + b * 2 + c * 3 + d * 4 + 1;
    59     int ra = 0, rb = 0, rc = 0, rd = 0;
    60     if(a > 0)    ra = dfs(a - 1, b, c, d);
    61     if(b > 0)    rb = dfs(a, b - 1, c, d);
    62     if(c > 0)    rc = dfs(a, b, c - 1, d);
    63     if(d > 0)    rd = dfs(a, b, c, d - 1);
    64     smax(f[a][b][c][d], max(ra, max(rb, max(rc, rd))) + val[pos]);
    65     return f[a][b][c][d];
    66 }
    67 
    68 inline void solve() {
    69     int res = dfs(counter[0], counter[1], counter[2], counter[3]);
    70     printf("%d", res);
    71 }
    72 
    73 int main() {
    74     freopen("tortoise.in", "r", stdin);
    75     freopen("tortoise.out", "w", stdout);
    76     init();
    77     solve();
    78     return 0;
    79 }


      这道题相当于是安排罪犯,使所有的影响力的最大值最小,于是就不难想到二分答案。

      对于当前二分值mid,无视所有权值小于等于它的边,判断是否能让剩下的边构成二分图。至于这一步多次对未访问的点进行dfs,将与它相连的点丢进另一个监狱,如果出现矛盾,就说明当前的二分值不合法。

    Code

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cctype>
      4 #include<cstring>
      5 #include<cstdlib>
      6 #include<fstream>
      7 #include<sstream>
      8 #include<algorithm>
      9 #include<map>
     10 #include<set>
     11 #include<queue>
     12 #include<vector>
     13 #include<stack>
     14 using namespace std;
     15 typedef bool boolean;
     16 #define INF 0xfffffff
     17 #define smin(a, b) a = min(a, b)
     18 #define smax(a, b) a = max(a, b)
     19 template<typename T>
     20 inline void readInteger(T& u){
     21     char x;
     22     int aFlag = 1;
     23     while(!isdigit((x = getchar())) && x != '-');
     24     if(x == '-'){
     25         x = getchar();
     26         aFlag = -1;
     27     }
     28     for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0');
     29     ungetc(x, stdin);
     30     u *= aFlag;
     31 }
     32 
     33 typedef class Edge {
     34     public:
     35         int end;
     36         int next;
     37         int w;
     38         Edge(const int end = 0, const int next = 0, const int w = 0):end(end), next(next), w(w) {        }
     39 }Edge;
     40 
     41 typedef class MapManager{
     42     public:
     43         int ce;
     44         int *h;
     45         Edge *edge;
     46         MapManager(){}
     47         MapManager(int points, int limit):ce(0){
     48             h = new int[(const int)(points + 1)];
     49             edge = new Edge[(const int)(limit + 1)];
     50             memset(h, 0, sizeof(int) * (points + 1));
     51         }
     52         inline void addEdge(int from, int end, int w){
     53             edge[++ce] = Edge(end, h[from], w);
     54             h[from] = ce;
     55         }
     56         inline void addDoubleEdge(int from, int end, int w){
     57             addEdge(from, end, w);
     58             addEdge(end, from, w);
     59         }
     60         Edge& operator [](int pos) {
     61             return edge[pos];
     62         }
     63 }MapManager;
     64 #define m_begin(g, i) (g).h[(i)]
     65 
     66 int n, m;
     67 MapManager g;
     68 int* belong;
     69 int maxval = -1;
     70 
     71 inline void init() {
     72     readInteger(n);
     73     readInteger(m);
     74     g = MapManager(n, 2 * m);
     75     belong = new int[(const int)(n + 1)];
     76     for(int i = 1, a, b, w; i <= m; i++) {
     77         readInteger(a);
     78         readInteger(b);
     79         readInteger(w);
     80         g.addDoubleEdge(a, b, w);
     81         smax(maxval, w);
     82     }
     83 }
     84 
     85 boolean dfs(int node, int val, int x) {
     86     if(belong[node] != -1)    return belong[node] == val;
     87     else    belong[node] = val;
     88     for(int i = m_begin(g, node); i != 0; i = g[i].next) {
     89         if(g[i].w <= x)    continue;
     90         int& e = g[i].end;
     91         if(!dfs(e, val ^ 1, x))    return false;
     92     }
     93     return true;
     94 }
     95 
     96 boolean check(int x) {
     97     memset(belong, -1, sizeof(int) * (n + 1));
     98     for(int i = 1; i <= n; i++) {
     99         if(belong[i] == -1)
    100             if(!dfs(i, 0, x))    return false;
    101     }
    102     return true;
    103 }
    104 
    105 inline void solve() {
    106     int l = 0, r = maxval;
    107     while(l <= r) {
    108         int mid = (l + r) >> 1;
    109         if(!check(mid))    l = mid + 1;
    110         else r = mid - 1;
    111     }
    112     printf("%d", r + 1);
    113 }
    114 
    115 int main() {
    116     freopen("prison.in", "r", stdin);
    117     freopen("prison.out", "w", stdout);
    118     init();
    119     solve();
    120     return 0;
    121 }


      对于可以使干旱区的每个城市都能够获得水的情况,那么对于湖泊边的某个城市建的蓄水厂,能够提供给干旱区的城市水的集合,是一段连续的区间。这里可以简要地说明一下

      假设上面的命题不成立,就会出现形如上面的情况,那么为了使中间的小圆圈所在的城市可以得到供水,那么一定会有其他的水路和这几条水路交叉,也就是说这个蓄水厂还是可以给小圆圈所在的城市供水,矛盾,所以上面的命题成立。

      于是我们可以通过M次dfs得到假设在第一行第i个城市建蓄水厂所能够供水的区间,当然这样的时间复杂度最极端的情况下是O(m2n)。但是仔细一想,对于一个点(i,j)它可以到达的干旱区城市,那么某个可以到达它的点(i+a,j+b)一定也可以到达它所可以到达的干旱区城市,于是只需要一些dfs从没有被访问的第一行的城市开始搜索,因为每个城市只会被访问一次,所以时间复杂度为O(mn),降回了可以接受的范围。

      得到了这么一堆区间可以干什么?我们是需要选择一些区间使得它们的并集是整个干旱区,于是可以用dp[i]来表示完全覆盖干旱区第1个城市到第j个城市的最小所需的区间,于是又得到了方程:

    Code

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cctype>
      4 #include<cstring>
      5 #include<cstdlib>
      6 #include<fstream>
      7 #include<sstream>
      8 #include<algorithm>
      9 #include<map>
     10 #include<set>
     11 #include<queue>
     12 #include<vector>
     13 #include<stack>
     14 using namespace std;
     15 typedef bool boolean;
     16 #define INF 0xfffffff
     17 #define smin(a, b) a = min(a, b)
     18 #define smax(a, b) a = max(a, b)
     19 template<typename T>
     20 inline void readInteger(T& u){
     21     char x;
     22     int aFlag = 1;
     23     while(!isdigit((x = getchar())) && x != '-');
     24     if(x == '-'){
     25         x = getchar();
     26         aFlag = -1;
     27     }
     28     for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0');
     29     ungetc(x, stdin);
     30     u *= aFlag;
     31 }
     32 
     33 typedef class Point {
     34     public:
     35         int x, y;
     36         int l, r;
     37         
     38         Point(const int x = 0, const int y = 0, const int l = 0, const int r = 0):x(x), y(y), l(l), r(r) {        }
     39         
     40         boolean mergable(Point& b) {
     41             if(b.l < l)    return true;
     42             if(b.r > r)    return true;
     43             return false;
     44         }
     45         void merge(Point& b) {
     46             smin(l, b.l);
     47             smax(r, b.r);
     48         }
     49 }Point;
     50 
     51 int n, m;
     52 int mat[505][505];
     53 
     54 inline void init() {
     55     readInteger(n);
     56     readInteger(m);
     57     for(int i = 1; i <= n; i++) {
     58         for(int j = 1; j <= m; j++) {
     59             readInteger(mat[i][j]);
     60         }
     61     }
     62 }
     63 
     64 const int mover[2][4] = {{0, 1, 0, -1}, {1, 0, -1, 0}};
     65 
     66 Point f[505][505];
     67 boolean vis[505][505];
     68 Point dfs(int x, int y) {
     69     if(vis[x][y])    return f[x][y];
     70     vis[x][y] = true;
     71     f[x][y] = Point(x, y, 999, 0);
     72     if(x == n)    f[x][y] = Point(x, y, y, y);
     73     for(int k = 0; k < 4; k++) {
     74         int x1 = x + mover[0][k], y1 = y + mover[1][k];
     75         if(x1 < 1 || x1 > n)    continue;
     76         if(y1 < 1 || y1 > m)    continue;
     77         if(mat[x1][y1] < mat[x][y]) {
     78             Point e = dfs(x1, y1);
     79             f[x][y].merge(e);
     80         }
     81     }
     82     return f[x][y];
     83 }
     84 
     85 void dfs1(int x, int y) {
     86     if(vis[x][y])    return;
     87     vis[x][y] = true;
     88     for(int k = 0; k < 4; k++) {
     89         int x1 = x + mover[0][k], y1 = y + mover[1][k];
     90         if(x1 < 1 || x1 > n)    continue;
     91         if(y1 < 1 || y1 > m)    continue;
     92         if(mat[x1][y1] < mat[x][y]) {
     93             Point e = dfs(x1, y1);
     94             f[x][y].merge(e);
     95         }
     96     }
     97 }
     98 
     99 int *dp;
    100 inline void solve() {
    101     memset(vis, false, sizeof(vis));
    102     for(int i = 1; i <= m; i++)
    103         if(!vis[1][i])
    104             dfs(1, i);
    105     dp = new int[(const int)(m + 2)];
    106     memset(dp, 0, sizeof(int) * (m + 2));
    107     for(int i = 1; i <= m; i++)
    108         if(f[1][i].l < 999)
    109             dp[f[1][i].l] += 1, dp[f[1][i].r + 1] -= 1;
    110     int unget = 0;
    111     for(int i = 1; i <= m; i++) {
    112         if(!vis[n][i])
    113             unget++;
    114     }
    115     if(unget > 1) {
    116         printf("0
    %d", unget);
    117         return;
    118     }
    119     memset(dp, 0x7f, sizeof(int) * (m + 2));
    120     dp[0] = 0;
    121     for(int i = 1; i <= m; i++) {
    122         for(int j = 1; j <= m; j++) {
    123             if(f[1][j].l > i || f[1][j].r < i)    continue;
    124             smin(dp[i], dp[f[1][j].l - 1] + 1);
    125         }
    126     }
    127     printf("1
    %d", dp[m]);
    128 }
    129 
    130 int main() {
    131     freopen("flow.in", "r", stdin);
    132     freopen("flow.out", "w", stdout);
    133     init();
    134     solve();
    135     return 0;
    136 }
  • 相关阅读:
    Springboot演示小Demo
    快速构建一个 Springboot
    javase练习题--每天写写
    javase练习题
    WebDriver API——延时操作及元素等待
    WebDriver API——javascript的相关操作
    Jenkins安装部署及tomcat的入门介绍
    WebDriver API——鼠标及键盘操作Actions
    sql查询练习
    睡前反省,絮叨絮叨
  • 原文地址:https://www.cnblogs.com/yyf0309/p/6413588.html
Copyright © 2011-2022 走看看