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\n", 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\n", 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\n", 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\n", 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\n", 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\n", 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\n", 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\n", 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;
}

 

posted @ 2018-02-03 16:38  Fighting_Heart  阅读(474)  评论(0编辑  收藏  举报