• 2015 Multi-University Training Contest 8


    Hdu 5385 The path

      题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5385

      题意:有一个联通的有向图,d(x)用来记录从1点到x点的最短路径长度,d(1)=0;一个图可以称之为好图是存在一个x使得d(1)<d(2)<....d(x)>d(x+1)>...d(n), 现在你要设置每一条边的长度使得这个图是一个好图,注意,满足d(1)<d(2)<..d(n)的也是一个好图。边的长度在1~n的范围内。一定存在解决方案。

      思路:按照题解说的模拟构造就行了,如下: 我们可以采取贪心做法,一开始将1号点作为最短路径树的根,然后左边从2开始,右边从n开始,只要之前加入的点有边连向他们就加入,这样一个点加入的时间就是他的dis值,最短路径树上的父亲也可以确定,于是输出时非树边长度为n,树边长度为两个端点dis之差

      参考代码:

     1 #include <iostream>
     2 #include <cmath>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <string>
     6 #include <cstdio>
     7 #include <vector>
     8 using namespace std;
     9 #define M 300010
    10 int dis[M], f[M], head[M];
    11 int cnt;
    12 struct node
    13 {
    14     int from, to, next;
    15 } edge[M * 2 + 10];
    16 void addedge(int a, int b)
    17 {
    18     edge[cnt].from = a;
    19     edge[cnt].to = b;
    20     edge[cnt].next = head[a];
    21     head[a] = cnt++;
    22 }
    23 void add(int x)
    24 {
    25     for (int i = head[x]; i!=-1; i = edge[i].next)
    26     {
    27         int v = edge[i].to;
    28         if (!f[v])
    29             f[v] = x;
    30     }
    31 }
    32 int main()
    33 {
    34     int T, n, m, a, b;
    35     scanf("%d", &T);
    36     while (T--)
    37     {
    38         memset(f, 0, sizeof(f));
    39         memset(head, -1, sizeof(head));
    40         f[1] = -1;
    41         dis[1] = 0;
    42         cnt = 0;
    43         scanf("%d%d", &n, &m);
    44         for (int i = 0; i < m; i++)
    45         {
    46             scanf("%d%d",&a, &b);
    47             addedge(a, b);
    48         }
    49         int num = 1, l = 1, r = n;
    50         while (l <= r)
    51         {
    52             if (f[l])
    53             {
    54                 add(l);
    55                 dis[l++] = num++;
    56             }
    57             if (f[r])
    58             {
    59                 add(r);
    60                 dis[r--] = num++;
    61             }
    62         }
    63         for (int i = 0; i < cnt; i++)
    64         {
    65             a = edge[i].from;
    66             b = edge[i].to;
    67             if (f[b] != a)//不在最短路树上的边
    68                 printf("%d
    ", n);
    69             else
    70                 printf("%d
    ", dis[b] - dis[a]);//最短路树上的边
    71         }
    72     }
    73     return 0;
    74 }
    View Code

    Hdu 5386 Cover

     

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5386

    题意:有一个n*n的矩阵,矩阵的每一个方格都有颜色,有以下两种操作:

        L x y: for(int i=1;i<=n;i++)color[i][x]=y;
       H x y:for(int i=1;i<=n;i++)color[x][i]=y;

       现在给你矩阵的初始状态和最终状态,m种操作,写出这些操作的顺序使的经过这些操作后,矩阵从初始状态变成最终状态;

    思路:逆向思维。
       
    最后一个操作肯定是把某一行或者某一列变成x,我们倒过来模拟,每次把最后一个操作找出来,即每次找到某一行或者某一列不为0的数都相同的,再找符合操作的。

    参考代码:

      1 #include <iostream>
      2 #include <cmath>
      3 #include <algorithm>
      4 #include <cstring>
      5 #include <string>
      6 #include <cstdio>
      7 #include <vector>
      8 using namespace std;
      9 #define M 505
     10 #define N 105
     11 #define MOD 258280327
     12 int  n, m, h, l;
     13 #define inf 0x3f3f3f3f
     14 bool vish[M], visl[M];
     15 int G[N][N];
     16 struct node
     17 {
     18     int color, id, x;
     19 } oph[M], opl[M];
     20 int path[M];
     21 int judge(int x, int color, int dix)
     22 {
     23     if (dix == 1)
     24     {
     25         for (int i = 1; i <= n; i++)
     26         {
     27             if (G[x][i] == inf)
     28                 continue;
     29             if (G[x][i] != color)
     30                 return false;
     31         }
     32     }
     33     else
     34     {
     35         for (int i = 1; i <= n; i++)
     36         {
     37             if (G[i][x] == inf)
     38                 continue;
     39             if (G[i][x] != color)
     40                 return false;
     41         }
     42     }
     43 }
     44 void setcolor(int x, int dix)
     45 {
     46     if (dix == 1)
     47     {
     48         for (int i = 1; i <= n; i++)
     49             G[x][i] = inf;
     50     }
     51     else
     52     {
     53         for (int i = 1; i <= n; i++)
     54             G[i][x] = inf;
     55     }
     56 }
     57 void solve()
     58 {
     59     int cnt = 0;
     60     while (cnt < m)
     61     {
     62         for (int i = 0; i < h; i++)//试每一种没有使用过的纵向操作
     63         {
     64             if (vish[i])
     65                 continue;
     66             if (judge(oph[i].x, oph[i].color, 1))
     67             {
     68                 setcolor(oph[i].x, 1);
     69                 vish[i] = true;
     70                 path[cnt++] = oph[i].id;//把操作序号记录下来
     71             }
     72         }
     73         for (int i = 0; i < l; i++)
     74         {
     75             if (visl[i])
     76                 continue;
     77             if (judge(opl[i].x, opl[i].color, 2))
     78             {
     79                 setcolor(opl[i].x, 2);
     80                 visl[i] = true;
     81                 path[cnt++] = opl[i].id;
     82             }
     83         }
     84     }
     85 }
     86 int main()
     87 {
     88     int T;
     89     scanf("%d", &T);
     90     while (T--)
     91     {
     92         scanf("%d%d", &n, &m);
     93         int temp;
     94         //初始状态是不用记录的
     95         for (int i = 1; i <= n; i++)
     96             for (int j = 1; j <= n; j++)
     97                 scanf("%d", &temp);
     98         for (int i = 1; i <= n; i++)
     99         {
    100             for (int j = 1; j <= n; j++)
    101                 scanf("%d", &G[i][j]);
    102         }
    103         memset(vish, 0, sizeof(vish));//记录纵向操作是否操作过
    104         memset(visl, 0, sizeof(visl));//记录横向操作是否操作过
    105         char op[2];
    106         int x, color;
    107         h = 0;
    108         l = 0;
    109         for (int i = 1; i <= m; i++)
    110         {
    111             scanf("%s%d%d", op, &x, &color);
    112             if (op[0] == 'H')
    113             {
    114                 oph[h].x = x;
    115                 oph[h].color = color;
    116                 oph[h++].id = i;
    117             }
    118             else
    119             {
    120                 opl[l].x = x;
    121                 opl[l].color = color;
    122                 opl[l++].id = i;
    123             }
    124         }
    125         solve();
    126         //打印路径
    127         for (int i = m - 1; i >= 0; i--)
    128         {
    129             if (i == m - 1)
    130                 printf("%d", path[i]);
    131             else
    132                 printf(" %d", path[i]);
    133         }
    134         printf("
    ");
    135     }
    136     return 0;
    137 }
    View Code

    Hdu 5387 Clock

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5387

    题意:给你一个时间,输出时分秒三个指针之间的角度(0~180),注意:实数用最简分数表示,整数直接输出。

    思路:简单题。

    参考代码:

     1 #include <iostream>
     2 #include <cmath>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <string>
     6 #include <cstdio>
     7 #include <vector>
     8 using namespace std;
     9 #define ang 3600
    10 typedef long long ll;
    11 int gcd(int a,int b){
    12     return b==0?a:gcd(b,a%b);
    13 }
    14 void calangle(int a,int b)  
    15 {  
    16     int sum;  
    17     if(abs(a-b)>30*6*ang)  
    18         sum=60*6*ang-abs(a-b);  
    19     else  
    20         sum=abs(a-b);  
    21     if(sum%ang)  
    22     {  
    23         int d=gcd(sum,ang);  
    24         printf("%d/%d ",sum/d,ang/d);  
    25     }  
    26     else  
    27         printf("%d ",sum/ang);  
    28 }  
    29 int main()  
    30 {  
    31     int i,j,k,h,m,s,t;  
    32     char c;  
    33     scanf("%d",&t);  
    34     while(t--)  
    35     {  
    36         scanf("%d%c%d%c%d",&h,&c,&m,&c,&s);  
    37         if(h>=12)  
    38             h=h-12;  
    39         int ss=ang*s*6;  
    40         int mm=(60*s+ang*m)*6;  
    41         int hh=((s+60*m)*5+h*ang*5)*6;  
    42         calangle(hh,mm);  
    43         calangle(hh,ss);  
    44         calangle(mm,ss);  
    45         printf("
    ");  
    46     }  
    47     return 0;  
    48 }  
    View Code

    Hdu 5387 Zero Escape

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5389

    题意:给你n个人每个人手里有一个id,然后给你两个数a和b,让你把n个人分为两组,条件是 一组人手里的id和等于a 另一组人的id和等于b,这里的和是指加起来之后对9取余,如果sum等于0 则sum等于9 否则sum = sum;还有一种情况也可以 就是所有人的id和等于a 或者等于b 相当于分为一组。

    思路:

      dp[i][j]=dp[i-1][j]+dp[i-1][tmp](tmp为j-arr[i],若小于等于0,需加9调整)

        dp[i][j]含义为取前i个数字中的若干个,按给定规则,算出来的和为j的方案数

        之前有两个细节没考虑到,

        一是、当前位和我dp[i][j]中的j值相同,那么对应三种情况。

        1.当前位不取,直接取前面dp[i-1][j]的值

        2.当前位取,前面取的是dp[i-1][9]的值(因为加9,不变)

        3.当前位取,前面都不取,此种情况特殊,直接加一即可。

        其实2、3两种情况是一个数分别对应dp[i-1][0]和dp[i-1][9]的特殊情况。

        二是、当a+b的和和sum相同时,最后输出结果的时候,按理说只要输出dp[n][a]就可以了,但是这样会遗漏a中都不取,全都放在b中,而b又刚好和sum相同的情况。

    参考代码:

     1 #include <iostream>
     2 #include <cmath>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <string>
     6 #include <cstdio>
     7 #include <vector>
     8 using namespace std;
     9 #define M 100005
    10 #define MOD 258280327
    11 int num[M];
    12 int dp[M][10];
    13 int cal(int n)
    14 {
    15     int k=0;
    16     while(n)
    17     {
    18         k+=(n%10);
    19         n/=10;
    20     }
    21     if(k>9)
    22         return cal(k);
    23     else
    24         return k;
    25 }
    26 int main()
    27 {
    28     int T,a,b,n,temp,sum;
    29     scanf("%d",&T);
    30     while(T--)
    31     {
    32         memset(dp,0,sizeof(dp));
    33         sum=0;
    34         scanf("%d%d%d",&n,&a,&b);
    35         for(int i=1;i<=n;i++)
    36         {
    37             scanf("%d",&num[i]);
    38             num[i]=cal(num[i]);
    39             sum+=num[i];
    40         }
    41         sum=cal(sum);
    42         int s=a+b;
    43         s=cal(s);
    44         if(sum==s)
    45         {
    46             dp[1][num[1]]=1;
    47             for(int i=2;i<=n;i++)
    48             {
    49                 for(int j=1;j<=9;j++)
    50                 {
    51                     temp=j-num[i];
    52                     if(temp<=0)
    53                         temp+=9;
    54                     dp[i][j]=(dp[i-1][temp]+dp[i-1][j])%MOD;
    55                 }
    56             }
    57             printf("%d
    ",(dp[n][a]+dp[n][b])%MOD);
    58         }
    59         else
    60         {
    61             int ans=0;
    62             if(sum==a)
    63                 ans++;
    64             if(sum==b)
    65                 ans++;
    66             printf("%d
    ",ans);
    67         }
    68     }
    69     return 0;
    70 }
    View Code
  • 相关阅读:
    CICD : 存代码部署(精简版)
    CICD:通过Shell 将打包后的代码部署到各环境
    linux:curl 取得HTTP返回的状态码
    闭包简单的了解
    javascript正则表达式了解
    搭建PHP开发环境(四)-PHP操作MySQL
    搭建PHP开发环境(三)-MySQL安装配置
    搭建PHP开发环境(二)-PHP安装
    搭建PHP开发环境(一)-Apache安装配置
    生成简单验证码文字
  • 原文地址:https://www.cnblogs.com/PJQOOO/p/4734680.html
Copyright © 2020-2023  润新知