zoukankan      html  css  js  c++  java
  • 2017-2018 ACM-ICPC, Asia Daejeon Regional Contest

    先来一个大神的全题解:http://blog.myungwoo.kr/121

    A. Broadcast Stations

    B. Connect3

    题意:在一个4*4的棋盘上玩游戏,先手执黑,后手执白。每次一位玩家选一个未填满的column,在其中row id最小的位置放下自己的棋子。如果连续的三个棋子同色(同行/同列/同对角线),游戏结束,下最后一步的人获胜。下面给你一组询问,(x, a, b) (1 <= x, a, b <= 4),问你先手第一步下(1, x),且游戏的最后一步是后手下白棋在(a, b)时,棋盘的最终形态有多少种。

    思考:发现可以用三进制数(3^16)表示棋盘,0表示空,1表示黑棋,2表示白棋。暴力搜索即可。如果是多组询问,还可以把4*4*4中询问的结果本地打表。

    代码:

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 typedef  long long ll;
      5 typedef pair<int, int> ii;
      6 typedef pair<ll, ll> l4;
      7 typedef pair<ii, int> iii;
      8 #define mp make_pair
      9 #define pb push_back
     10 
     11 const int N = 43046721;
     12 int p[16];
     13 int ans[4][4][4]={0};
     14 int d[N]={0};
     15 int x;
     16 inline int getp(int x, int y)
     17 {
     18   return p[x*4+y];
     19 }
     20 inline int get(const int &bit, int x, int y)
     21 {
     22   int a = x*4+y;
     23   return bit/p[a]%3;
     24 }
     25 inline bool check(const int &bit, int x, int y, int win=2, bool print=false)
     26 {
     27   if (print)
     28     cerr << "check " << x << " " << y << " " << win << endl;
     29   //check vertical
     30   bool work;
     31 
     32   for (int i = max(0, x-2); i <= min(x, 1); ++i)
     33      {
     34       work = true;
     35       for (int j = 0; j < 3; ++j)
     36     if (get(bit, i+j, y) != win)
     37       {
     38         work = false;
     39         break;
     40       }
     41       if (work)
     42     {
     43       if (print) cerr << i << " to " << x+2 << " at y = " << y << endl;
     44       return true;
     45     }
     46     }
     47   //check horizontal
     48   for (int i = max(0, y-2); i <= min(y, 1); ++i)
     49     {
     50       work = true;
     51       for (int j = 0; j < 3; ++j)
     52     if (get(bit, x, i+j) != win)
     53       {
     54         work = false;
     55         break;
     56       }
     57       if (work)
     58     {
     59       if (print) cerr << "at x = "<< x << " " << i << " to " << i+2 << endl;
     60       return true;
     61     }
     62     }
     63   //check dia
     64   int tx = x, ty = y;
     65   while (tx > 0 && ty > 0)
     66     --tx, --ty;
     67   while (tx+2 < 4 && ty+2<4)
     68     {
     69       work = true;
     70       for (int j = 0; j < 3; ++j)
     71     if (get(bit, tx+j, ty+j) != win)
     72       {
     73         work = false;
     74         break;
     75       }
     76       if (work)
     77     {
     78       if (print) cerr << tx << " to " << tx+2 << " and " << ty << " " << ty+2 << endl;
     79       return true;
     80     }
     81       ++tx, ++ty;
     82     }
     83   //check anti dia
     84   tx = x, ty = y;
     85   while (tx > 0 && ty < 3)
     86     --tx, ++ty;
     87   while (tx+2<4 && ty-2>=0)
     88     {
     89       work = true;
     90       for (int j = 0; j < 3; ++j)
     91     if (get(bit, tx+j, ty-j) != win)
     92       {
     93         work = false;
     94         break;
     95       }
     96       if (work)
     97     {
     98       if (print) cerr << tx << " to " << tx+2 << " and " << ty << " " << ty-2 << endl;
     99       return true;
    100     }
    101       ++tx, --ty;
    102     }
    103   return false;
    104 }
    105 void print(int cur)
    106 {
    107   return;
    108   cerr << endl << "print
    ";
    109   for (int i = 0; i < 4; ++i, cerr << endl)
    110     for (int j = 0; j < 4; ++j)
    111       {
    112     cerr << get(cur, i, j);
    113       }
    114 }
    115 int solve(int xx, int aa, int bb)
    116 {
    117   int ret = 0;
    118   x = xx;
    119   memset(d, 0, sizeof(d));
    120   queue<int> q, nq;
    121   int cur = 0;
    122   cur = 1*getp(0, xx);
    123   q.push(cur);
    124   d[cur] = -1;
    125   set<int> st;
    126   while (!q.empty())
    127     {
    128       while (!q.empty())
    129     {
    130       int cur = q.front();
    131       q.pop();
    132       if (get(cur, aa, bb) != 0)
    133         continue;
    134 
    135       for (int j = 0; j < 4; ++j)
    136         for (int i = 0; i < 4; ++i)
    137           if (get(cur, i, j) == 0)
    138         {
    139           //          cerr << "can go " << i << "," << j << endl;
    140           int nxt = cur + 2 * getp(i, j);
    141           if (check(nxt, i, j))
    142             {
    143               if (i == aa && j == bb)
    144             {
    145               st.insert(nxt);
    146             }
    147             }
    148           else
    149             {
    150               if (d[nxt])
    151             break;
    152               else
    153             {
    154               d[nxt] = -1;
    155               nq.push(nxt);
    156             }
    157             }
    158           break;
    159         }
    160     }
    161       //      cerr << "nq
    ";
    162       while (!nq.empty())
    163     {
    164       int cur = nq.front();
    165       nq.pop();
    166       if (get(cur, aa, bb) != 0)
    167         continue;
    168 
    169       for (int j = 0; j < 4; ++j)
    170         for (int i = 0; i < 4; ++i)
    171           if (get(cur, i, j) == 0)
    172         {
    173           int nxt = cur + getp(i, j);
    174           if (d[nxt])
    175             break;
    176           if (check(nxt, i, j, 1))
    177             break;
    178           d[nxt] = -1;
    179           q.push(nxt);
    180           break;
    181         }
    182     }
    183     }
    184   /*
    185   for (int i = 0; i < 200; ++i)
    186     {
    187       cerr << i << endl;
    188       check(*st.begin(), aa, bb, 2, true);
    189       print(*st.begin());
    190       st.erase(st.begin());
    191     }
    192   */
    193   return st.size();
    194 }
    195 int main()
    196 {
    197   p[0] = 1;
    198   for (int i = 1; i < 16; ++i)
    199     p[i] = p[i-1]*3;
    200   assert(N == p[15]*3);
    201   int a, b, c;
    202   scanf("%d %d %d", &c, &a, &b);
    203   printf("%d
    ", solve(c-1, a-1, b-1));
    204 }
    View Code

    赛后:

    比赛中写的很麻烦,主要是因为一开始读错了题,没有看到每一步只能下在一个column的最低位置。现在想想,可不可以直接枚举棋盘的终止状态,判断(a, b)是否可以是最后一步即可。

    但其实实现发现有很多细节需要考虑,主要是检查当前棋盘是否是一个合法的游戏状态。最好的方法还是由合法状态bfs到其他状态

    C. Game Map

    题意:n <= 1e5 个点,m <= 3e5 条边的无向图。从任意一点出发,只能向度数比当前点的度数大的点走。求最长的路径上有多少个点。

    观察:要求路径上点度数严格递增,其实已经给边定了方向且无环。所以本质就是DAG上的最长路,记忆画搜索即可。

    代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 typedef  long long ll;
     5 typedef pair<int, int> ii;
     6 typedef pair<ll, ll> l4;
     7 typedef pair<ii, int> iii;
     8 #define mp make_pair
     9 #define pb push_back
    10 
    11 
    12 
    13 const int maxn = 1e5+1;
    14 int n, m;
    15 vector<int> g[maxn];
    16 int d[maxn];
    17 
    18 int dp(int cur)
    19 {
    20   int &ret = d[cur];
    21   if (ret == -1)
    22     {
    23       ret = 1;
    24       for (int i = 0; i < g[cur].size(); ++i)
    25     {
    26       int nxt = g[cur][i];
    27       if (g[nxt].size() > g[cur].size())
    28         ret = max(ret, 1+dp(nxt));
    29     }
    30     }
    31   return ret;
    32 }
    33 
    34 
    35 int main()
    36 {
    37   scanf("%d %d", &n, &m);
    38   for (int i = 0; i < m; ++i)
    39     {
    40       int a, b;
    41       scanf("%d %d", &a, &b);
    42       g[a].pb(b);
    43       g[b].pb(a);
    44     }
    45   memset(d, -1, sizeof(d));
    46   int ans = 1;
    47   for (int i = 0; i < n; ++i)
    48     ans = max(ans, dp(i));
    49   printf("%d
    ", ans);
    50 }
    View Code

    D. Happy Number

    题意:f(n) = n各数位平方的和。如果存在一个k使得f^k(n) = 1, 那么就说n是happy的。可以发现,如果n不是happy的,那么一定存在一个p使得f^p(n) = n。下面给你一个询问n<=1e9,让你输出他是否happy。

    观察:对于n <= 1e9, f(n) <= max(9*9^2, f(1e9)) = 9^3。直接暴力计算,遇到循环终止。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 
     5 bool vis[1000];
     6 int f(int n)
     7 {
     8   int ret = 0;
     9   while (n)
    10     {
    11       int tmp = n%10;
    12       n /= 10;
    13       ret += tmp * tmp;
    14     }
    15   return ret;
    16 }
    17 bool solve(int n)
    18 {
    19   if (n == 1)
    20     return true;
    21   if (vis[n])
    22     return false;
    23   vis[n] = true;
    24   return solve(f(n));
    25 }
    26 int main()
    27 {
    28   memset(vis, 0, sizeof(vis));
    29   int n;
    30   scanf("%d", &n);
    31   n = f(n);
    32   puts(solve(n)?"HAPPY":"UNHAPPY");
    33 }
    View Code

    E. How Many to Be Happy

    题意:边带权无向图G,对于一条边e,如果存在一个包含e的最小生成树,那么e就是happy的。定义H(e) 为 使e变为happy所需删掉的最少边数。输入一个n <= 100个点m<=500条边的图,让你输出所有边的H(e)之和。

    观察:对于一条边e(x, y, len),只有长度小len的边才会对H(e)产生影响(等于len的边不影响,可以考虑kruskal算法中,边权相同的边的位置可以随便更改)。而且边数点数都不多,也许可以每条边分别处理。那么考虑所有长度小于len的边的生成子图SubG,若想要e存在于某个mst,就要删掉最小的边使SubG中x和y不联通,可以发现就是要求最小割。

    F. Philosphoer's Walk

    题意:

    观察:大体可以看出是个recursion。

    G. Rectilinear Regions

    题意:给你两条阶梯线U和L,阶梯线是指非递增或者非递减的折线。每条阶梯线的拐点个数不超过25e3。保证两条直线的拐点没有重复的x或者y,让你求出U在上方L在下方的封闭空间的个数和面积和。

    观察:首先如果L和U的方向不同(一增一减),直接输出“0 0”。同减的情况可以转化成同增,方法是先把两条边上所有的y取相反数,然后交换U和L两条线。这样只需要考虑同增的情况。用一个sorted vector来保存拐点就好。小心一开始U就高于L的特殊情况,还有小心最后U高于L的情况。第一个特殊情况我是用一个bool first = true来标记,当L高于U的时候first = false,只有当first == false的时候才开始计算答案。第二个特殊情况我是记录一个tmparea,表示当前空间的面积,每当L高于U使得面积闭合的时候,我在吧tmparea更新到答案(同时更新封闭区间的个数)。

    代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 typedef  long long ll;
     5 typedef pair<int, int> ii;
     6 typedef pair<ll, ll> l4;
     7 typedef pair<ii, int> iii;
     8 #define mp make_pair
     9 #define pb push_back
    10 
    11 
    12 const int N = 25e3+10;
    13 struct Node
    14 {
    15   int x, y, id;
    16   bool operator<(const Node &r) const
    17   {
    18     return x < r.x;
    19   }
    20   void read(int xx)
    21   {
    22     scanf("%d %d", &x, &y);
    23     id =xx ;
    24   }
    25 } a[N], b[N], c[N<<1];
    26 
    27 
    28 int main()
    29 {
    30   int n, m;
    31   int y0, y1;
    32   scanf("%d %d", &n, &m);
    33   scanf("%d", &y0);
    34   for (int i = 0; i < n; ++i)
    35     a[i].read(0);
    36   scanf("%d", &y1);
    37   for (int i = 0; i < m; ++i)
    38     b[i].read(1);
    39   bool d1 = a[0].y > y0;
    40   bool d2 = b[0].y > y1;
    41   if (d1 != d2)
    42     {
    43       puts("0 0");
    44       return 0;
    45     }
    46   else if (d1 == 0)
    47     {
    48       y0 *= -1;
    49       y1 *= -1;
    50       for (int i = 0; i < n; ++i)
    51     a[i].y *= -1, a[i].id = 1;
    52       for (int j = 0; j < m; ++j)
    53     b[j].y *= -1, b[j].id = 0;
    54       swap(y0, y1);
    55       swap(a, b);
    56       swap(n, m);
    57     }
    58     
    59   //  cerr << "read done
    ";
    60   merge(a, a+n, b, b+m, c);
    61   int last=-1;
    62   ll ans = 0;
    63   ll tmp = 0;
    64   int ansans = 0;
    65   bool first = y1 > y0;
    66   for (int i = 0; i < n+m; ++i)
    67     {
    68       if (c[i].id == 0)
    69     {
    70       if (last != -1)
    71         {
    72           tmp += 1ll*(c[i].x-last)*(y1-y0);
    73           if (c[i].y < y1)
    74         last = c[i].x;
    75           else
    76         last = -1, ++ansans, ans += tmp, tmp = 0;
    77         }
    78       y0 = c[i].y;
    79       if (y0 >= y1)
    80         first = false;
    81     }
    82       else
    83     {
    84       if (last != -1)
    85         {
    86           tmp += 1ll*(c[i].x-last)*(y1-y0);
    87           last = c[i].x;
    88         }
    89       y1 = c[i].y;
    90       if (!first && last == -1 && y1 > y0)
    91         {
    92           last = c[i].x;
    93         }
    94     }
    95       //      cerr << c[i].id << " " << c[i].x << " " << c[i].y << " " << c[i].id <<" " << y0 << " " << y1 << " " << last <<  endl;
    96     }
    97   printf("%d %lld
    ", ansans, ans);
    98 }
    View Code

    H. Rock Paper Scissors

    大坑

    I. Slot Machines

    题意:给你一个长度为n<= 1e6的整数序列T[1-n],找到使得pair(k+p, p)最小的k和p,k和p要满足, T[i+p] = T[i] (k < i <= n-p)。

    方法:观察可知,对于一组(k, p),p为T[k+1, ..., n] 的周期,取最小的循环周期最优。而通过kmp可以O(n)预处理fail数组f[] 然后O(1)询问任意前缀的循环节长度(i-f[i]),所以只需要对T[1-n]反向求kmp得到fail数组,枚举k,p可以快速求出,更新答案。

    代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 typedef  long long ll;
     5 typedef pair<int, int> ii;
     6 typedef pair<ll, ll> l4;
     7 typedef pair<ii, int> iii;
     8 #define mp make_pair
     9 #define pb push_back
    10 
    11 
    12 
    13 
    14 const int maxn = 1e6+10;
    15 int a[maxn], f[maxn], n;
    16 int main()
    17 {
    18   scanf("%d", &n);
    19   for (int i = n-1; i >= 0; --i)
    20     {
    21       scanf("%d", a+i);
    22     }
    23   f[0] = -1;
    24   for (int i = 0, j = -1; i < n; ++i, ++j)
    25     {
    26       while (j != -1 && a[j] != a[i])
    27     j = f[j];
    28       f[i+1] = j+1;
    29     }
    30   int k = n, p = 1;
    31   for (int i = n; i >= 1; --i)
    32     {
    33       int kk = n-i;
    34       int pp = i-f[i];
    35       if (pp + kk < k+p)
    36     k = kk, p = pp;
    37       else if (pp + kk == k+p && pp < p)
    38     k = kk, p = pp;
    39     }
    40   printf("%d %d
    ", k, p);
    41 }
    View Code

    J. Strongly Matchable

    K. Untangling Chain

    题意:给你一个有n-1个拐点的折线 (n <= 1e5),要求你妥善安排每一个线段的长度,使得折线段不会自交。每一条线段的长度不能超过n。

    方法:如果n不是很大,可以使第i段线段的长度为2^i,这样一定不会自交。此时思路变成,可不可以使边长不断增大,使得后续的转弯不会受之前的影响。

    想了想可不可以直接把线段长度设成1-n,发现不行,比如假设从(0, 0)开始 右(1, 0) 上(1, 2) 右(1+3, 2) 上(1+3, 2+4) 右(1+3+5, 2+4) 下(1+3+5, 2+4-6) 左(1+3+5-7, 0)自交了。即如果在水平方向上(竖直方向类似),如果连续的几次运动都是朝着同一个自方向,那么我们的方案会使得这个方向的距离快速增加(即上述水平方向上连续三次向右的操作,总的看是连续向右了1+3+5 = 9个单位),那么下一次向反方向的操作(如上述的向左),就需要一个很大的长度(上述例子中至少需要9+1)。

    然后就想到了正确的做法。分开考虑水平方向和竖直方向。对于一个方向,考虑这个方向上第i次移动,如果方向和上一次相同,那么就走1的长度,不然就走i的长度。可以发现这样走,不管怎么样都不会自交。例子: 右上右上右下左 : 右(1, 0)上(1, 1)右(1+1, 1)上(2, 1+1)右(2+1, 2)下(3, 2-3)左(3-4, -1)

    代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=10005;
     4 const int dx[4]={0,0,-1,1};
     5 const int dy[4]={-1,1,0,0};
     6 int n,dir[maxn],s,lstx,lsty,res[maxn],ansx=1,ansy=1;
     7 inline void change(int dir, int &dx, int &dy)
     8 {
     9   if (dir == 1)
    10     {
    11       int ddx = -dy;
    12       int ddy = dx;
    13       dy = ddy;
    14       dx = ddx;
    15     }
    16   else
    17     {
    18       int ddx = dy;
    19       int ddy = -dx;
    20       dy = ddy;
    21       dx = ddx;
    22     }
    23 }
    24 int main()
    25 {
    26     scanf("%d",&n);
    27     for (int i=0;i<n;++i)
    28         scanf("%d%d",&s,&dir[i]);
    29     if (n==1)
    30         puts("1");
    31     else if (n==2)
    32         puts("1 2");
    33     else {
    34       int dx = 1, dy = 0;
    35       res[0] = 1;
    36       int last = 1;
    37       int cal = 1;
    38       for (int i = 1; i < n-1; i += 2)
    39     {
    40       change(dir[i-1], dx, dy);
    41       change(dir[i], dx, dy);
    42       ++cal;
    43       if (dx == last)
    44         {
    45           res[i+1] = 1;
    46         }
    47       else
    48         {
    49           res[i+1] = cal;
    50           last = dx;
    51         }
    52     }
    53       dx = 1, dy = 0;
    54       change(dir[0], dx, dy);
    55       last = dy;
    56       cal = 1;
    57       res[1] = 1;
    58       for (int i = 2; i < n-1; i += 2)
    59     {
    60       change(dir[i-1], dx, dy);
    61       change(dir[i], dx, dy);
    62       ++cal;
    63       if (last == dy)
    64         res[i+1] = 1;
    65       else
    66         res[i+1] = cal, last = dy;
    67     }
    68       res[n-1] = 1;
    69       /*
    70         lstx=dir[0],lsty=dir[1];
    71         res[0]=res[1]=1;
    72         for (int i=1;i<n;++i) {
    73             if (i%2==0) {
    74                 ++ansx;
    75                 if (dir[i]==lstx)
    76                     res[i]=1;
    77                 else
    78                     res[i]=ansx,lstx=-lstx;
    79             } else {
    80                 ++ansy;
    81                 if (dir[i]==lsty)
    82                     res[i]=1;
    83                 else
    84                     res[i]=ansy,lsty=-lsty;
    85             }
    86         }
    87       */
    88         for (int i=0;i<n;++i)
    89             printf("%d%c",res[i],i+1==n?'
    ':' ');
    90     }
    91     return 0;
    92 }
    View Code

    L. Vacation Plans

    题意:

  • 相关阅读:
    调度器2—cat /proc/<pid>/sched内容分析
    调度器1—相关接口和命令行工具
    Java中的String类
    Java中的数组
    代码访问使用Let's Encrypt证书的网站提示certificate has expired的解决方法
    Linux环境Clion使用Protobuf
    PyTorch Dataloader读取时如何在进程之间传输数据
    6 安装Grafana 展示promethues数据
    5 Prometheus relabel配置
    4 PromQL
  • 原文地址:https://www.cnblogs.com/skyette/p/8271006.html
Copyright © 2011-2022 走看看