zoukankan      html  css  js  c++  java
  • 2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 2) 题解

    题目链接

    A - Alphabet

    最长公共子序列。保留最长公共子序列,剩余的删除或者补足即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    char s[maxn];
    char t[maxn];
    int dp[100][100];
    
    int main() {
      scanf("%s", s);
      for(int i = 0; i < 26; i ++) {
        t[i] = i + 'a';
        t[i + 1] = 0;
      }
      int lens = strlen(s);
      int lent = strlen(t);
      for(int i = 1; i <= lens; i ++) {
        for(int j = 1; j <= lent; j ++) {
          if(s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
          else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
        }
      }
      printf("%d
    ", 26 - dp[lens][lent]);
      return 0;
    }
    

    B - Barbells

    暴力。枚举哪几个一定用,去剩余的那些里面枚举是否可以凑出和这几个一样的。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    int n, m;
    long long a[maxn], b[maxn];
    long long ans[maxn];
    long long p[maxn];
    long long sum[maxn];
    int sz, cnt;
    long long B[maxn];
    long long sumB[maxn];
    
    int lowbit(int x) {
      return x & (-x);
    }
    
    int main() {
      cin >> n >> m;
      for(int i = 0; i < n; i ++) cin >> a[i];
      for(int i = 0; i < m; i ++) cin >> b[i];
      for(int i = 1; i < (1 << m); i ++) {
        for(int j = 0; j < m; j ++) {
          if((1 << j) & i) sum[i] += b[j];
        }
      }
      for(int i = 0; i < (1 << m); i ++) {
        sz = 0;
        for(int j = 0; j < m; j ++) {
          if((1 << j) & i) continue;
          B[sz ++] = b[j];
        }
        // sum[i];
        if(sum[i] == 0) {
          p[cnt ++] = sum[i];
          continue;
        }
        sumB[0] = 0;
        for(int j = 0; j < sz; j ++) {
          sumB[1 << j] = B[j];
        }
        for(int j = 1; j < (1 << sz); j ++) {
          sumB[j] = sumB[j - lowbit(j)] + sumB[lowbit(j)];
          if(sumB[j] == sum[i]) {
            p[cnt ++] = sum[i];
            break;
          }
        }
      }
      sz = 0;
      for(int i = 0; i < cnt; i ++) {
        for(int t = 0; t < n; t ++) {
          ans[sz ++] = p[i] * 2 + a[t];
        }
      }
      sort(ans, ans + sz);
      for(int i = 0; i < sz; i ++) {
        if(i >= 1 && ans[i] == ans[i - 1]) continue;
        printf("%lld
    ", ans[i]);
      }
      
      return 0;
    }
    
    /*
     2 5
     100 110
     5 5 1 4 6
     
     */
    

    C - Buggy Robot

    记$f[i][x][y]$表示操作了前$i$个指令,当前在$(x,y)$位置的最小费用。分析可以发现是一个边权只有$0$和$1$的最短路问题。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 60;
    int dir[4][2] = {
      {-1, 0},
      {0, 1},
      {1, 0},
      {0, -1},
    };
    
    int n, m;
    char s[maxn][maxn];
    char op[maxn];
    int len;
    int dp[maxn][maxn][maxn];
    int f[maxn][maxn][maxn];
    int sx, sy, ex, ey;
    
    int out(int x, int y) {
      if(x < 0 || x >= n) return 1;
      if(y < 0 || y >= m) return 1;
      return 0;
    }
    
    int Hash(int a, int x, int y) {
      return a * 10000 + x * 100 + y;
    }
    
    void Get(int st, int &a, int &x, int &y) {
      y = st % 100;
      st = st / 100;
      x = st % 100;
      st = st / 100;
      a = st;
    }
    
    void work() {
      queue<int> q;
      dp[0][sx][sy] = 0;
      f[0][sx][sy] = 1;
      q.push(Hash(0, sx, sy));
      while(!q.empty()) {
        int st = q.front();
        q.pop();
        int a, x, y;
        Get(st, a, x, y);
        f[a][x][y] = 0;
        
        /* insert */
        for(int i = 0; i < 4; i ++) {
          int tx = x + dir[i][0];
          int ty = y + dir[i][1];
          if(out(tx, ty)) continue;
          if(s[tx][ty] == '#') continue;
          if(dp[a][tx][ty] > dp[a][x][y] + 1) {
            dp[a][tx][ty] = dp[a][x][y] + 1;
            if(f[a][tx][ty] == 0) {
              f[a][tx][ty] = 1;
              q.push(Hash(a, tx, ty));
            }
          }
        }
        
        /* del */
        if(a < len) {
          if(dp[a + 1][x][y] > dp[a][x][y] + 1) {
            dp[a + 1][x][y] = dp[a][x][y] + 1;
            if(f[a + 1][x][y] == 0) {
              f[a + 1][x][y] = 1;
              q.push(Hash(a + 1, x, y));
            }
          }
        }
        
        /* use */
        if(a < len) {
          int d;
          if(op[a] == 'U') d = 0;
          if(op[a] == 'R') d = 1;
          if(op[a] == 'D') d = 2;
          if(op[a] == 'L') d = 3;
          
          int tx = x + dir[d][0];
          int ty = y + dir[d][1];
          if(out(tx, ty) || s[tx][ty] == '#') {
            tx = x;
            ty = y;
          }
          if(dp[a + 1][tx][ty] > dp[a][x][y]) {
            dp[a + 1][tx][ty] = dp[a][x][y];
            if(f[a + 1][tx][ty] == 0) {
              f[a + 1][tx][ty] = 1;
              q.push(Hash(a + 1, tx, ty));
            }
          }
        }
      }
    }
    
    int main() {
      scanf("%d%d", &n, &m);
      for(int i = 0; i < n; i ++) {
        scanf("%s", s[i]);
      }
      scanf("%s", op);
      len = strlen(op);
      for(int i = 0; i < n; i ++) {
        for(int j = 0; j < m; j ++) {
          if(s[i][j] == 'R') sx = i, sy = j;
          if(s[i][j] == 'E') ex = i, ey = j;
          for(int k = 0; k <= len; k ++) {
            dp[k][i][j] = 100000;
          }
        }
      }
      work();
      int ans = 100000;
      for(int i = 0; i <= len; i ++) {
        ans = min(ans, dp[i][ex][ey]);
      }
      printf("%d
    ", ans);
      return 0;
    }
    
    /*
     3 3
     R..
     .#.
     ..E
     LRDD
     
     2 4
     R.#.
     #..E
     RRUUDDRRUUUU
     */
    

    D - Cameras

    贪心。每一个区间看,贪心靠后放$1$即可。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    int f[maxn];
    int n, k, r;
    
    int main() {
      scanf("%d%d%d", &n, &k, &r);
      for(int i = 1; i <= k; i ++) {
        int x;
        scanf("%d", &x);
        f[x] = 1;
      }
      int ans = 0;
      int sum = 0;
      for(int i = 1; i <= r; i ++) {
        sum += f[i];
      }
      int R = r;
      while(sum < 2) {
        if(f[R]) R --;
        else {
          sum ++;
          f[R] = 1;
          ans ++;
          R --;
        }
      }
      for(int i = r + 1; i <= n; i ++) {
        sum -= f[i - r];
        sum += f[i];
        int L = i - r + 1;
        int R = i;
        while(sum < 2) {
          if(f[R]) R --;
          else {
            sum ++;
            f[R] = 1;
            ans ++;
            R --;
          }
        }
      }
      printf("%d
    ", ans);
      return 0;
    }
    

    E - Contest Score

    优先队列。

    #include <bits/stdc++.h>
    using namespace std;
    
    int n, k;
    long long a[500];
    priority_queue<long long> p;
    
    int main() {
      scanf("%d%d", &n, &k);
      for(int i = 1; i <= n; i ++) {
        cin >> a[i];
      }
      long long ans = 0;
      long long time = 0;
      for(int i = 1; i <= k; i ++) {
        p.push(-a[i]);
      }
      for(int i = k + 1; i <= n; i ++) {
        long long u = -p.top();
        p.pop();
        time += u;
        ans += time;
        p.push(-a[i]);
      }
      while(!p.empty()) {
        long long u = -p.top();
        p.pop();
        time += u;
        ans += time;
      }
      cout << ans << endl;
      return 0;
    }
    

    F - Equality

    水题。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    char s[maxn];
    
    int main() {
      int a, b, c;
      cin >> a;
      cin >> s;
      cin >> b;
      cin >> s;
      cin >> c;
      if(a + b == c) puts("YES");
      else puts("NO");
      return 0;
    }
    

    G - Gravity

    模拟。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1000;
    char s[maxn][maxn];
    
    int main() {
      int n, m;
      scanf("%d%d", &n, &m);
      for(int i = 0; i < n; i ++) {
        scanf("%s", s[i]);
      }
      for(int i = n - 2; i >= 0; i --) {
        for(int j = 0; j < m; j ++) {
          if(s[i][j] != 'o') continue;
          int x = i;
          for(int k = i + 1; k < n; k ++) {
            if(s[k][j] == '.') x = k;
            else break;
          }
          s[i][j] = '.';
          s[x][j] = 'o';
        }
      }
      for(int i = 0; i < n; i ++) {
        printf("%s
    ", s[i]);
      }
      return 0;
    }
    
    /*
     3 3
     ooo
     #..
     ..#
     
     
     4 2
     oo
     oo
     o.
     ..
     */
    

    H - Islands

    从每一个未被遍历过的$L$开始遍历,$C$当做$L$。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1010;
    char s[maxn][maxn];
    int n, m;
    int ans;
    
    int f[maxn][maxn];
    int dir[4][2] = {
      {0, -1},
      {0, 1},
      {1, 0},
      {-1, 0},
    };
    
    int out(int x, int y) {
      if(x < 0 || x >= n) return 1;
      if(y < 0 || y >= m) return 1;
      return 0;
    }
    
    void dfs(int x, int y) {
      f[x][y] = 1;
      for(int i = 0; i < 4; i ++) {
        int tx = x + dir[i][0];
        int ty = y + dir[i][1];
        if(out(tx, ty)) continue;
        if(s[tx][ty] == 'W') continue;
        if(f[tx][ty]) continue;
        dfs(tx, ty);
      }
    }
    
    int main() {
      scanf("%d%d", &n, &m);
      for(int i = 0; i < n; i ++) {
        scanf("%s", s[i]);
      }
      for(int i = 0; i < n; i ++) {
        for(int j = 0; j < m; j ++) {
          if(f[i][j]) continue;
          if(s[i][j] == 'L') {
            dfs(i, j);
            ans ++;
          }
        }
      }
      cout << ans << endl;
      return 0;
    }
    
    /*
     4 5 CCCCC CCCCC CCCCC CCCCC
     3 2 LW CC WL
     */
    

    I - Mismatched Socks

    二分。和这里的F题一样的做法,不再赘述。

    #include <bits/stdc++.h>
    using namespace std;
    
    int T, n, k;
    const int maxn = 1e5 + 10;
    long long a[maxn];
    
    int check(long long x) {
      long long p = 0;
      for(int i = 1; i <= n; i ++) {
        p = p + min(x, a[i]);
      }
      if(p >= x * k) return 1;
      return 0;
    }
    
    int main() {
    
        scanf("%d", &n);
        k = 2;
        for(int i = 1; i <= n; i ++) {
          scanf("%lld", &a[i]);
        }
        long long L = 0;
        long long R = 1e12;
        long long ans = 0;
        while(L <= R) {
          long long mid = (L + R) / 2;
          if(check(mid)) ans = mid, L = mid + 1;
          else R = mid - 1;
        }
        printf("%lld
    ", ans);
      
      return 0;
    }
    

    J - Postman

    贪心。原点左侧和右侧分开计算。每一侧计算的时候由远及近进行操作即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    struct X {
      long long x;
      long long m;
    }s[maxn];
    int n;
    long long k;
    
    bool cmp(const X& a, const X& b) {
      return a.x < b.x;
    }
    
    int main() {
      scanf("%d%lld", &n, &k);
      for(int i = 1; i <= n; i ++) {
        scanf("%lld%lld", &s[i].x, &s[i].m);
      }
      sort(s + 1, s + 1 + n, cmp);
      long long ans = 0;
      int p;
      if(s[1].x <= 0) {
        for(int i = 1; i <= n; i ++) {
          if(s[i].x <= 0) p = i;
        }
        while(1) {
          int now = -1;
          for(int i = 1; i <= p; i ++) {
            if(s[i].m) {
              now = i;
              break;
            }
          }
          if(now == -1) break;
          if(s[now].m >= k) {
            long long ci = s[now].m / k;
            ans = ans - ci * s[now].x;
            s[now].m = s[now].m % k;
          } else {
            long long tmp = k;
            ans = ans - s[now].x;
            while(tmp) {
              if(now > p) break;
              long long A = min(tmp, s[now].m);
              tmp = tmp - A;
              s[now].m -= A;
              now ++;
            }
          }
        }
      }
      p = -1;
      for(int i = 1; i <= n; i ++) {
        if(s[i].x > 0) {
          p = i;
          break;
        }
      }
      if(p != -1) {
        while(1) {
          int now = -1;
          for(int i = p; i <= n; i ++) {
            if(s[i].m) {
              now = i;
            }
          }
          if(now == -1) break;
          if(s[now].m >= k) {
            long long ci = s[now].m / k;
            ans = ans + ci * s[now].x;
            s[now].m = s[now].m % k;
          } else {
            long long tmp = k;
            ans = ans + s[now].x;
            while(tmp) {
              if(now < p) break;
              long long A = min(tmp, s[now].m);
              tmp = tmp - A;
              s[now].m -= A;
              now --;
            }
          }
        }
      }
      cout << ans * 2LL << endl;
      return 0;
    }
    
    
    /*
     4 10
     -7 5
     -2 3
     5 7
     9 5
     
     
     7 1
     9400000 10000000
     9500000 10000000
     9600000 10000000
     9700000 10000000
     9800000 10000000
     9900000 10000000
     10000000 10000000
     */
    

    K - Six Sides

    模拟。操作的次数越多,答案精度越高。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1000;
    int a[maxn], b[maxn];
    
    int main() {
      double ping = 0;
      double win = 0;
      for(int i = 1; i <= 6; i ++) cin >> a[i];
      for(int i = 1; i <= 6; i ++) cin >> b[i];
      for(int i = 1; i <= 6; i ++) {
        for(int j = 1; j <= 6; j ++) {
          if(a[i] == b[j]) ping ++;
          if(a[i] > b[j]) win ++;
        }
      }
      ping /= 36.0;
      win /= 36.0;
      double ans = 0.0;
      double x = 1.0;
      for(int i = 1; i <= 1000000; i ++) {
        ans = ans + x * win;
        x = x * ping;
      }
      printf("%.5f
    ", ans);
      return 0;
    }
    

    L - Three Square

    暴力枚举所有情况。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 5e5 + 10;
    int n, m;
    int a[maxn], b[maxn];
    int t[maxn];
    
    int A[maxn], B[maxn];
    
    int main() {
      
      cin >> a[0] >> b[0];
      cin >> a[1] >> b[1];
      cin >> a[2] >> b[2];
      
      
      t[0] = 0, t[1] = 1, t[2] = 2;
      
      int ok = 0;
      
      do {
       // printf("%d %d %d
    ", t[0], t[1], t[2]);
        for(int i = 0; i < 8; i ++) {
          for(int j = 0; j < 3; j ++) {
            if((i << j) & i) {
              B[j] = a[t[j]];
              A[j] = b[t[j]];
            } else {
              A[j] = a[t[j]];
              B[j] = b[t[j]];
            }
          }
          
          // 1
          if(A[0] == A[1] && A[0] == A[2]
             && B[0] + B[1] + B[2] == A[0]) ok = 1;
          
          // 2
          if(B[0] == B[1] && B[0] == B[2]
             && A[0] + A[1] + A[2] == B[0]) ok = 1;
          
          // 3
          if(B[1] + B[2] == B[0] && A[1] == A[2]
             && A[1] + A[0] == B[0]) ok = 1;
          
          // 5
          if(B[1] == B[2] && A[1] + A[2] == A[0]
             && A[0] == B[0] + B[1]) ok = 1;
          
        }
      } while(next_permutation(t, t + 3));
      
      if(ok) puts("YES");
      else puts("NO");
      
      return 0;
    }
    

    M - Zigzag

    记录以每个位置为结尾的且在波峰以及波谷的最长序列长度,和LIS一样转移即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 2000000;
    
    int n;
    int d[maxn];
    int dp[maxn][2];
    
    int main() {
      cin >> n;
      for(int i = 1; i <= n; i ++) {
        cin >> d[i];
      }
      int ans = 0;
      for(int i = 1; i <= n; i ++) {
        int mx = 0;
        // dp[i][0];
        for(int j = 1; j < i; j ++) {
          if(d[j] > d[i]) mx = max(mx, dp[j][1]);
        }
        dp[i][0] = mx + 1;
        ans = max(ans, dp[i][0]);
        
        mx = 0;
        // dp[i][1];
        for(int j = 1; j < i; j ++) {
          if(d[j] < d[i]) mx = max(mx, dp[j][0]);
        }
        dp[i][1] = mx + 1;
        ans = max(ans, dp[i][1]);
      }
      cout << ans << endl;
      return 0;
    }
    
  • 相关阅读:
    神秘题目4
    神秘题目3
    神秘题目2
    AC自动机
    Fence Obstacle Course 题解
    Fractal Streets
    龟速乘
    快速幂
    Stall Reservation
    Sunscreen
  • 原文地址:https://www.cnblogs.com/zufezzt/p/8409867.html
Copyright © 2011-2022 走看看