• 2012 MUTC 10 总结(The Final MUTC of this Summer)


    题解链接:http://page.renren.com/601081183/note/867254911

    题目编号:hdu 4390~4399

      这是杭电多校联合的最后一场比赛了,直到最后的这场比赛我们队在比赛中的题目数还是没有突破3题的局限。

      今天比赛开始的时候,依然是我的队友读题,而我就随便看了一题在一边想。第一题看到的就是1001,一道排列组合的题目。这几天都有看排列组合的题,不过基本上都不能1y,所以这题我想了一下,翻了一下《组合数学》,然后就放弃了。1001的思路是有的,不过就是不会后期的计算。组合数学是我的弱项,之后的学习必须要加强!

      然后就是队友看的1004,刚开始,我想着暴力寻找,用线段树更新,不过到后来才发现用线段树更新结点还是要变成逐个更新。于是,我就没辙了,丢给队友想。

      这时,发现1007也有很多人过,所以我就改向去看1007了。听队友讲了一下题意,我基本明白了题目的意思。当时我想了一下最短路来算这个,不过好像不能得到准确的答案,而且操作起来又或者最后的还是有点麻烦的。于是,当时我就想到层次遍历,利用上一层的结果得到当前步数到达各点的最短时间,如果到满足要求的那一层,汇点的状态是无穷大,那么就是不可达。不过我想深一层的时候,发现有可能走多很多条路才得到最优解。于是,我又卡住了。不过很快的,我就想到一个特点,至少要走的那k层走够了以后,其余的部分不就是可以随便走,不过最后要走到汇点吗?然后我就倒过来想,求了以汇点作为源点到其他各点的最短路,然后将两个操作合并起来,最后不就可以得到满足题意的最优解了吗?  最终的代码很快就完成了,不过打错了一点东西,搞到我又debug了好久。不过庆幸的是,在我思路清晰的情况下,打出来的代码提交就是一个1y~赛后看了一下题解,貌似题解的方法会比我的慢上好多。

    1007(hdu 4396):

    View Code
      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cstring>
      4 #include <vector>
      5 #include <cmath>
      6 #include <algorithm>
      7 
      8 using namespace std;
      9 const int maxn = 5002;
     10 const int inf = 0x7f7f7f7f;
     11 const int maxe = 100001;
     12 
     13 struct edge{
     14     int s;
     15     int t;
     16     int cost;
     17     void ins(int a, int b, int c){
     18         s = a; t = b; cost = c;
     19     }
     20     bool operator < (const edge &x) const{
     21         return s < x.s;
     22     }
     23 }E[maxe << 1];
     24 int dis[maxn], re[maxn], ld[maxn], dd[maxn];
     25 int q[maxn << 2], qh, qt;
     26 bool inq[maxn];
     27 
     28 void spfa(int n, int s){
     29     int cur, es, et;
     30 
     31     qh = qt = 0;
     32     q[qt++] = s;
     33     for (int i = 1; i <= n; i++){
     34         dd[i] = inf;
     35         inq[i] = false;
     36     }
     37     dd[s] = 0;
     38 
     39     while (qh < qt){
     40         cur = q[qh++];
     41         inq[cur] = false;
     42         for (int i = re[cur]; i < re[cur + 1]; i++){
     43             es = E[i].s;
     44             et = E[i].t;
     45             if (dd[et] > dd[es] + E[i].cost){
     46                 dd[et] = dd[es] + E[i].cost;
     47                 if (!inq[et]){
     48                     q[qt++] = et;
     49                     inq[et] = true;
     50                 }
     51             }
     52         }
     53     }
     54 }
     55 
     56 void pre_deal(int n, int m){ // 预处理每一条边,方便之后的使用
     57     int p = 0;
     58 
     59     sort(E, E + m);
     60     for (int i = 0; i < m; i++){
     61 #ifndef ONLINE_JUDGE
     62         printf("%d : %d %d  %d\n", i, E[i].s, E[i].t, E[i].cost);
     63 #endif
     64         while (p <= E[i].s){
     65             re[p] = i;
     66             p++;
     67         }
     68     }
     69     for (int i = p; i <= n + 1; i++){
     70         re[i] = m;
     71     }
     72 #ifndef ONLINE_JUDGE
     73     for (int i = 0; i <= n + 1; i++){
     74         printf("%d : %d\n", i, re[i]);
     75     }
     76 #endif
     77 }
     78 
     79 void deal(int n, int s, int t ,int k){
     80     int es, et;
     81 
     82     for (int i = 1; i <= n; i++){
     83         ld[i] = inf;
     84         dis[i] = inf;
     85     }
     86     ld[s] = 0;
     87     while (k--){
     88 #ifndef ONLINE_JUDGE
     89         puts("status:");
     90         for (int i = 1; i <= n; i++){
     91             printf("%d: %d\n", i, ld[i]);
     92         }
     93 #endif
     94         for (int i = 1; i <= n; i++){
     95             if (ld[i] != inf){
     96                 for (int j = re[i]; j < re[i + 1]; j++){
     97                     es = E[j].s;
     98                     et = E[j].t;
     99                     if (dis[et] > ld[es] + E[j].cost)
    100                         dis[et] = ld[es] + E[j].cost;
    101                 }
    102             }
    103         }
    104         for (int i = 1; i <= n; i++){
    105             ld[i] = dis[i];
    106             dis[i] = inf;
    107         }
    108     }
    109 }
    110 
    111 int final(int n){
    112     int ret = inf;
    113 
    114     for (int i = 1; i <= n; i++){
    115 #ifndef ONLINE_JUDGE
    116         printf("%d : %d %d\n", i, dd[i], ld[i]);
    117 #endif
    118         if (dd[i] != inf && ld[i] != inf){
    119             if (ret > dd[i] + ld[i])
    120                 ret = dd[i] + ld[i];
    121         }
    122     }
    123 
    124     if (ret == inf) return -1;
    125     return ret;
    126 }
    127 
    128 int main(){
    129     int n, m;
    130     int s, t, c;
    131     int i1, i2;
    132 
    133     while (~scanf("%d%d", &n, &m)){
    134         for (int i = 0; i < m; i++){
    135             scanf("%d%d%d", &s, &t, &c);
    136             i1 = i << 1; i2 = i << 1 | 1;
    137             E[i1].ins(s, t, c);
    138             E[i2].ins(t, s, c); // 双向边
    139         }
    140         m <<= 1;
    141         pre_deal(n, m);
    142         scanf("%d%d%d", &s, &t, &c);
    143         c = (c - 1) / 10 + 1;
    144         deal(n, s, t, c); // 正向遍历最少经过路的数目,不超过50
    145         spfa(n, t); // 反向找到到汇点的所有最短路
    146         printf("%d\n", final(n)); // 结合两个结果得到答案
    147     }
    148 
    149     return 0;
    150 }

      在我打1007的时候,队友想到了1004其实在500次暴力枚举后,每个人的速度就会稳定,之后就不会出现人与人间超越的情况了。当时我想了一下,觉得好像挺有道理的,于是在我想到spfa前就让队友打出他的代码。不过打出来的代码提交wa了,后来我想到1007的解法了,我就拿过键盘,队友在隔壁的电脑查看自己的代码。在我打完1007并且通过了以后,队友还在卡1004。于是我就提出我重新打这个程序的要求。当然,他们也同意了。在我快打完的时候,我突然想到队友的代码缺少了一个条件,于是我就问了一下他是否有写排编号的条件。果然,队友添加上去后就ac了!不过我也尝试着交我的代码,不过是wa的......- -     赛后检查了代码,才发现原来是排序写少了一个+1,所以wa了,过过来就ac了!

    1004(hdu 4393):

    View Code
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <cmath>
     5 #include <cstdlib>
     6 
     7 using namespace std;
     8 
     9 const int maxn = 50005;
    10 const int inf = 0x7f7f7f7f;
    11 
    12 struct point{
    13     int cur;
    14     int s;
    15     int num;
    16     bool operator < (const point &x) const {
    17         if (cur != x.cur) return cur > x.cur;
    18         return num < x.num;
    19     }
    20 }p[maxn];
    21 
    22 void deal(int cc){
    23     int n, t;
    24     int maxcur, mk;
    25     bool fs = true;
    26 
    27     scanf("%d", &n);
    28     for (int i = 1; i <= n; i++){
    29         scanf("%d%d", &p[i].cur, &p[i].s);
    30         p[i].num = i;
    31     }
    32     printf("Case #%d:\n", cc);
    33     if (n <= 550) t = n;
    34     else t = 550;
    35     for (int i = 1; i <= t; i++){ // 暴力搜索未稳定时的序列
    36         maxcur = -inf;
    37         for (int j = 1; j <= n; j++){
    38             if (maxcur < p[j].cur){
    39                 maxcur = p[j].cur;
    40                 mk = j;
    41             }
    42             p[j].cur += p[j].s;
    43         }
    44         p[mk].cur = -inf;
    45         if (fs){
    46             printf("%d", mk);
    47             fs = false;
    48         }
    49         else printf(" %d", mk);
    50     }
    51     if (n > 550){
    52         sort(p + 1, p + n + 1);
    53         for (int i = 1, endi = n - 550; i <= endi; i++){
    54             printf(" %d", p[i].num);
    55         }
    56     }
    57     puts("");
    58     
    59 }
    60 
    61 int main(){
    62     int T;
    63 
    64     scanf("%d", &T);
    65     for (int i = 1; i <= T; i++){
    66         deal(i);
    67     }
    68 
    69     return 0;
    70 }

      过了这题,还剩一个半小时,于是我们就集中想了1005。当时已经想到了逐位搜索,不过就是没有总结出一个系统的做法,所以在最后40分钟的时候,我尝试着逐步打出来,不过最后还是打出了一个烂程序,连sample都不能过。回到宿舍以后再打,wa了好几次。在debug的时候,发现我的代码要加好多补丁,所以我就直接放弃了代码,用另一种方法来打这题!

      1005在确定最后第k位的时候,当前得到的数的平方的最后k位必须要和目标尾数的最后k位相同才能继续进行下去。然后dfs一下,得到下面的代码!

    1005(hdu 4394):

    View Code
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <cmath>
     5 #include <cstdlib>
     6 
     7 using namespace std;
     8 
     9 const int maxn = 50005;
    10 const int inf = 0x7f7f7f7f;
    11 
    12 struct point{
    13     int cur;
    14     int s;
    15     int num;
    16     bool operator < (const point &x) const {
    17         if (cur != x.cur) return cur > x.cur;
    18         return num < x.num;
    19     }
    20 }p[maxn];
    21 
    22 void deal(int cc){
    23     int n, t;
    24     int maxcur, mk;
    25     bool fs = true;
    26 
    27     scanf("%d", &n);
    28     for (int i = 1; i <= n; i++){
    29         scanf("%d%d", &p[i].cur, &p[i].s);
    30         p[i].num = i;
    31     }
    32     printf("Case #%d:\n", cc);
    33     if (n <= 550) t = n;
    34     else t = 550;
    35     for (int i = 1; i <= t; i++){
    36         maxcur = -inf;
    37         for (int j = 1; j <= n; j++){
    38             if (maxcur < p[j].cur){
    39                 maxcur = p[j].cur;
    40                 mk = j;
    41             }
    42             p[j].cur += p[j].s;
    43         }
    44         p[mk].cur = -inf;
    45         if (fs){
    46             printf("%d", mk);
    47             fs = false;
    48         }
    49         else printf(" %d", mk);
    50     }
    51     if (n > 550){
    52         sort(p + 1, p + n + 1);
    53         for (int i = 1, endi = n - 550; i <= endi; i++){
    54             printf(" %d", p[i].num);
    55         }
    56     }
    57     puts("");
    58     
    59 }
    60 
    61 int main(){
    62     int T;
    63 
    64     scanf("%d", &T);
    65     for (int i = 1; i <= T; i++){
    66         deal(i);
    67     }
    68 
    69     return 0;
    70 }

      这次数学知识占的比例比较高,以后的目标还是要在搞好基础算法的同时,训练好数学思维!

    ——written by Lyon

  • 相关阅读:
    [转发]UML类图符号 各种关系说明以及举例
    Promise 对象
    ES6基础(二)
    ES6基础
    JSON介绍
    Ajax的面试题
    Ajax请求
    jQuery从小白开始---初始jQuery
    常用的String原型
    JS之类数组
  • 原文地址:https://www.cnblogs.com/LyonLys/p/2012MUTC10_Lyon.html
Copyright © 2020-2023  润新知