SDNU 训练赛总结
 
ACM训练 
A题 思路 就是简单的排个序,输出第K大小的数字,同时将前K大的数字的标号输出来。因为文件WA的自闭,QWQ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include  <iostream>  #include  <algorithm>  #include  <cstring>  #include  <string>  #include  <stdio.h>  using  namespace  std;struct  node {   int  index;    int  v; }a[1010 ]; int  cmp (node a,node b)  {    return  a.v > b.v; } int  main ()  {    int  n,k;     freopen ("input.txt" ,"r" ,stdin);   freopen ("output.txt" ,"w" ,stdout);     scanf ("%d %d" ,&n,&k);     for (int  i = 1 ; i <= n; ++i)     {         scanf ("%d" ,&a[i].v);         a[i].index = i;     }     sort (a + 1 , a + n + 1 ,cmp);     printf ("%d\n" ,a[k].v);     for (int  i = 1 ; i <= k; ++i)     {         printf ("%d%c" ,a[i].index,i == k ?'\n' :' ' );     } } 
 
B题 题意 有N个人,他们分别有weight,beautiful, 现在让你挑选多个人,使得不超过总权重M的情况下,总的beautiful值最大。但是一些人可能是朋友,对于一个朋友组,要么选择不超过一个人,要么选择所有人。
思路 我们先用并查集把属于一个朋友群的人放到一个集合里。然后一个集合一个集合的枚举。对于每个集合,也是分别枚举一个人的情况和所有人的情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #include  <iostream>  #include  <cstdio>  #include  <cstring>  #include  <algorithm>  #include  <cmath>  #include  <bits/stdc++.h>  #include  <stack>  #include  <map>  int  f[1010 ], dp[2010 ], w[2001 ],b[2001 ];using  namespace  std;int  find (int  x)  {    if (x != f[x])         f[x] = find (f[x]);     return  f[x]; } void  combine (int  x,int  y)  {    int  fa = find (x);     int  fb = find (y);     if (fa != fb)         f[fa] = fb; } int  main ()  {    int  n, m ,W, aa, bb, num;     vector<int >V[2001 ];     cin >> n >> m >> W;     for (int  i = 1 ; i <= n; ++i)         f[i] = i;     for (int  i = 1 ; i <= n; ++i)         cin >> w[i];     for (int  i = 1 ; i <= n; ++i)         cin >> b[i];     while (m--)     {         cin >> aa >> bb;         combine (aa,bb);     }     for (int  i = 1 ; i <= n; ++i)         V[find (i)].push_back (i);     for (int  i = 1 ; i <= n; ++i)     {         if (i == find (i)){         for (int  j = W; j >= 0  ; --j)         {             int  sum1 = 0 ;             int  sum2 = 0 ;             for (int  k = 0 ; k < V[i].size (); ++k)             {                 num = V[i][k];                 sum1 += w[num];                 sum2 += b[num];                 if (j >= w[num])                 {                     dp[j] = max (dp[j], dp[j - w[num]] + b[num]);                 }             }             if (j >= sum1)                 dp[j] = max (dp[j], dp[j - sum1] + sum2);         }         }     }     cout << dp[W] << '\n' ; } 
 
C题 题意 给你一些钱币的组合总数,让你输出应该怎么组合。我们应该用1和2来进行组合即可。比如说输入314,那么如果钱币只有1和2的话,所达到的金额数应该是2 * n - 1.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include  <iostream>  #include  <cstdio>  #include  <cstring>  #include  <algorithm>  #include  <cmath>  #include  <bits/stdc++.h>  #include  <stack>  #include  <map>  using  namespace  std;int  main ()  {    int  n;     cin >> n;     cout << 2  * n - 1  << ' '  << 2  << '\n' ;     cout << 1  << ' '  << 2  << '\n' ; } 
 
D题 思路 对于一个N * N的矩阵,他有N / 2+1 个奇数,我们只需要合理的安排其中的位置,剩下的填上偶数就行了。每行每列以及对角线上的奇数的个数都应该是奇数个,因此最后我们构造的矩阵中间的菱形,也是正方形都是奇数,剩下的都是偶数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include  <iostream>  #include  <cstdio>  #include  <cstring>  #include  <algorithm>  #include  <cmath>  #include  <bits/stdc++.h>  #include  <stack>  #include  <map>  using  namespace  std;int  main ()  {    int  a[50 ][50 ], n;     cin >> n;     int  cnt = 1 ;     int  tot = 2 ;     int  cx = n / 2  + 1 ;     int  cy = cx;     for (int  i = 1 ; i <= n; ++i)     {         for (int  j = 1 ; j <= n; ++j)         {             if (abs (cx - i) + abs (cy - j) < n / 2  + 1 )                 {                     a[i][j] = cnt;                     cnt += 2 ;                 }             else              {                 a[i][j] = tot;                 tot += 2 ;             }         }     }     for (int  i = 1 ; i <= n; ++i)     {         for (int  j = 1 ; j <= n; ++j)         {             printf ("%d%c" ,a[i][j],j == n ? '\n' :' ' );         }     } } 
 
E题 思路 题意中是一种递归的算法。但是我们可以直接模拟贪心思路。把所有的数字放到一个数组里,然后从大到小排序。我们分别取前1个数字的最大数(相当于总矩阵的最大值),然后取前四个数字的最大值(相当于4个子矩阵的每个矩阵的最大值),然后是前16个….. 这样我们就不需要在构造出矩阵才能求最大值了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include  <iostream>  #include  <cstdio>  #include  <cstring>  #include  <algorithm>  #include  <cmath>  #include  <bits/stdc++.h>  #include  <stack>  #include  <map>  using  namespace  std;bool  cmp (int  a, int  b)  {    return  a > b; } int  a[20000010 ];int  main ()  {    int  n;     cin >> n;     for (int  i = 1 ; i <= n; ++i)         scanf ("%d" ,&a[i]);     sort (a + 1 ,a + n + 1 ,cmp);     int  k = 1 ;     long  long  sum;     while (k <= n)     {         for (int  i = 1 ; i <= k; ++i)         {             sum += a[i];         }         k *= 4 ;     }     cout << sum << '\n' ; } 
 
F题 题意 给你三种topo图,然后数据之后,问你属于哪种topo.
思路 只要记录每个节点的度即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include  <bits/stdc++.h>  using  namespace  std;int  vis[100001 ];int  main ()  {    int  n, m, a, b;     memset (vis, 0  ,sizeof (vis));     cin >> n >> m;     for (int  i = 1 ; i <= m; ++i)     {         cin >> a >> b;         vis[a]++;         vis[b]++;     }     int  cnt = 0  , cnt1 = 0 , cnt2 = 0 ;     for (int  i = 1 ; i <= n; ++i)     {         if (vis[i] == 1 )             cnt++;         if (vis[i] == 2 )             cnt1++;         if (vis[i] == n - 1 )             cnt2++;     }     if (cnt == 2  && cnt1 == n - 2 )         cout << "bus topology"  << '\n' ;     else  if (cnt1 == n)         cout << "ring topology"  << '\n' ;     else  if (cnt == n - 1  && cnt2 == 1 )         cout <<  "star topology"  << '\n' ;     else          cout << "unknown topology"  << '\n' ; } 
 
G题 思路 我们可以把总的花费时间求出来,然后看看这个总时间是否在一段区间内,在的话,最终的答案就是这个总时间。否则,答案是距离这个总时间最近的那个时间。在第11个样例错的,是没有考虑在还没有工作时间之前就已经完成任务的情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 #include  <iostream>  #include  <cstdio>  #include  <cstring>  #include  <algorithm>  #include  <cmath>  #include  <bits/stdc++.h>  #include  <stack>  #include  <map>  using  namespace  std;struct  node {   int  l,r; }b[2001 ]; int  a[1010 ], c[2001 ];bool  cmp (node a, node b)  {    if (a.l != b.l)         return  a.l < b.l;     else  return  a.r < b.r; } int  main ()  {    int  n, m;     cin >> n;     int  sum = 0 ;     for (int  i = 1 ; i <= n; ++i)     {         scanf ("%d" ,&a[i]);         sum += a[i];     }     cin >> m ;     int  max1 = -1 ;     for (int  i = 1 ; i <= m; ++i)     {         scanf ("%d %d" ,&b[i].l,&b[i].r);         if (max1 < b[i].r)             max1 = b[i].r;         c[i - 1 ] = b[i].l;     }     if (sum > max1)     {         cout << "-1"  << '\n' ;     }     else  if (sum < b[1 ].l)                 {         cout << b[1 ].l << '\n' ;     }     else {         sort (b + 1 , b + m + 1 , cmp);         int  flag = 0 ;         for (int  i = 1 ; i <= m; ++i)         {             if (b[i].l <= sum && b[i].r >= sum)             {                 flag = 1 ;                 cout << sum << '\n' ;                 break ;             }         }         if (!flag)         {            int  d = lower_bound (c , c + m , sum) - c ;            cout << c[d] << '\n' ;         }     } } 
 
H题 思路 本来想N*N的复杂度,发现不行,后来看这个是有序的,那就二分。用lower_bound函数比较简单一些。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include  <iostream>  #include  <algorithm>  #include  <cstring>  #include  <string>  using  namespace  std;struct  node {   int  c,t; }a[100010 ]; int  sum[100010 ];int  main ()  {    int  n,m,k;     cin >> n >> m;     for (int  i = 1 ; i <= n; ++i)     {         scanf ("%d %d" ,&a[i].c,&a[i].t);          }     sum[0 ] = 0 ;     for (int  i = 1 ; i <= n; ++i)     {         sum[i] = sum[i - 1 ] + a[i].c * a[i].t;     }     for (int  i = 1 ; i <= m; ++i)     {         scanf ("%d" ,&k);         int  m = lower_bound (sum + 1 , sum + n + 1 ,k) - (sum + 1 );         if (sum[m] == k)              cout << m << '\n' ;         else               cout << m + 1  << '\n' ;     } }