2015 ACM Amman Collegiate Programming Contest 题解

 

题目链接

 

A - Who Is The Winner

模拟。

#include <bits/stdc++.h>
using namespace std;

int T;
int n;
struct X {
  string name;
  int num;
  int ti;
}s[10010];

bool cmp(X&a,X&b){
  if(a.num != b.num) return a.num > b.num;
  return a.ti < b.ti;
}

int main() {
  scanf("%d", &T);
  while(T--) {
    scanf("%d",&n);
    for(int i=0;i<n;i++){
      cin>>s[i].name;
      cin>>s[i].num;
      cin>>s[i].ti;
      
     // cout << i << endl;
    }
    
    for(int i = 0; i < n; i ++) {
      //cout << s[i].name << " " << s[i].num << " " << s[i].ti << endl;
    }
    sort(s, s+n, cmp);
    cout << s[0].name<<endl;
  }
  return 0;
}
/*
 2
 3
 tourist 13 567
 petr 13 600
 endagorion 144 19
 2
 tourist 7 512
 bayashout ​7 477
 
 */

 

B - Rock-Paper-Scissors

枚举 $x$ 和 $y$,确定z,然后区间和算一下就能算出来谁赢了。

#include <bits/stdc++.h>
using namespace std;

int T;
int n;
char s[1010];

int sum[1010][3];

int Get(int L, int R, int num) {
  if(R < L) return 0;
  return sum[R][num] - sum[L-1][num];
}

int check(int x, int y, int z) {
  //[1,x]  R
  //[x+1,x+y]  P
  //[x+y+1,x+y+z]  S
  
  int point1 = Get(1,x,1);
  int pin1 = Get(1,x,0);
  int point2 = Get(x+1,x+y,0);
  int pin2 = Get(x+1,x+y,2);
  int point3 = Get(x+y+1,x+y+z,2);
  int pin3 = Get(x+y+1,x+y+z,1);
  
 // cout << point1 << " "<< point2 << " " << point3 << endl;
  
  int point_first = point1+point2+point3;
  int point_second = n - point_first - pin1 - pin2-pin3;
  
  if(point_first > point_second) return 1;
  return 0;
  
}

int main() {
  scanf("%d", &T);
  while(T--) {
    scanf("%d", &n);
    scanf("%s", s);
    memset(sum, 0, sizeof sum);
    for(int i = 0; s[i]; i ++) {
      sum[i+1][0] = sum[i][0];
      sum[i+1][1] = sum[i][1];
      sum[i+1][2] = sum[i][2];
      if(s[i] == 'R') sum[i+1][0] ++;
      if(s[i] == 'S') sum[i+1][1] ++;
      if(s[i] == 'P') sum[i+1][2] ++;
    }
    
    int ans = 0;
    int len = strlen(s);
    for(int x = 0; x <= len; x ++) {
      for(int y = 0; y <= len; y ++) {
        if(x + y > len) continue;
        int z = len - x - y;
        ans = ans + check(x, y, z);
      }
    }
    printf("%d\n", ans);
  }
  return 0;
}

 

C - Street Lamps

先把照亮的都确定一下,然后看连续的没被照亮的有几个,算一下就好了。

#include <bits/stdc++.h>
using namespace std;

int T,n;
char s[100010];

int cal(int x) {
  if(x == 0) return 0;
  int res = x / 3;
  if(x % 3) res ++;
  return res;
}

int main() {
  scanf("%d",&T);
  while(T--) {
    scanf("%d",&n);
    scanf("%s",s);
    int ans = 0;
    int len = strlen(s);
    for(int i = 0; s[i]; i++) {
      if(s[i] == '*') {
        if(i - 1 >= 0 && s[i-1] == '.') s[i -1] = '0';
        if(i + 1 < len && s[i+1] == '.') s[i+1] = '0';
      }
    }
    
    int num = 0;
    for(int i = 0; s[i]; i ++) {
      if(s[i] != '.') {
        ans = ans + cal(num);
        num = 0;
      } else {
        num ++;
      }
    }
    ans = ans + cal(num);
    printf("%d\n", ans);
  }
  return 0;
}

 

D - Alternating Strings

$dp_i$ 表示前缀需要分割成几段,枚举上一次断开的位置即可。

#include <bits/stdc++.h>
using namespace std;

int T;
int n, k, len;
char s[1010];
int dp[1010];
int jiao[1010][1010];


int Get(int x) {
  if(x == -1) return 0;
  return dp[x];
}

int main() {
  scanf("%d", &T);
  while(T--) {
    memset(jiao,0,sizeof jiao);
    scanf("%d%d",&n,&k);
    scanf("%s",s);
    len = strlen(s);
    
    for(int i = 0; i < len; i ++) {
      if(i + 1 < len) {
        if(s[i] != s[i + 1]) jiao[i][i + 1] = 1;
      }
      for(int j = i + 2; j < len; j ++) {
        if(s[j] != s[j - 1] && jiao[i][j - 1]) jiao[i][j] = 1;
      }
    }
    
    for(int i = 0; i < n; i ++) {
      for(int j = i; j < n; j ++) {
      //  cout << i << " " << j << " " << jiao[i][j] << endl;
      }
    }
    
    dp[0] = 1;
    for(int i = 1; i < n; i ++) {
      dp[i] = 100000;
      for(int j = i - 1; j >= -1; j --) {
        // [j+1, i]
        if(i - j > k) continue;
        if(jiao[j+1][i]) continue;
        dp[i] = min(dp[i], Get(j) + 1);
      }
    }
    
    printf("%d\n", dp[len - 1] - 1);
  }
  return 0;
}

 

E - Epic Professor

模拟。

#include <bits/stdc++.h>
using namespace std;

int T;
int n;
int x[100010];

int main() {
  scanf("%d", &T);
  while(T--) {
    scanf("%d",&n);
    int ans = 0;
    int cha = 1000;
    for(int i=0;i<n;i++){
      cin>>x[i];
      cha = min(cha, 100 - x[i]);
    }
    
    for(int i = 0; i<n;i++) {
      if(x[i] + cha >= 50) ans ++;
    }
    
    cout << ans << endl;
  }
  return 0;
}

 

F - Travelling Salesman

克鲁斯卡尔执行过程中,最小生成树上最大的边权就是答案。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5+10;
int T;
int n,m;
struct Edge {
  int u, v;
  int c;
}e[maxn];

int f[maxn];

int Find(int x) {
  if(x != f[x]) f[x] = Find(f[x]);
  return f[x];
}

bool cmp(Edge&a,Edge&b){
  return a.c<b.c;
}

int main() {
  scanf("%d", &T);
  while(T--) {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)f[i]=i;
    for(int i=1;i<=m;i++){
      scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].c);
    }
    sort(e+1,e+1+m,cmp);
    int ans = 0;
    for(int i=1;i<=m;i++){
      int fu=Find(e[i].u);
      int fv=Find(e[i].v);
      if(fu==fv)continue;
      f[fu]=fv;
      ans=e[i].c;
    }
    printf("%d\n",ans);
  }
  return 0;
}

/*
 2
 6 7
 1 2 3
 2 3 3
 3 1 5
 3 4 4
 4 5 4
 4 6 3
 6 5 5
 
 3 3
 1 2 1
 2 3 2
 3 1 3
 
 */

 

G - Heavy Coins

状压一下,某个状态是否可行,只要看看扔掉任意一个,是否都是不可行的。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5+10;
int T;
int n;
int s;

int dp[1200];
int sum[1200];

int a[20];

int lowbit(int x) {
  return x & (-x);
}

int main() {
  scanf("%d",&T);
  while(T--) {
    scanf("%d%d", &n, &s);
    for(int i = 0; i < n; i ++) {
      scanf("%d", &a[i]);
    }
    for(int i = 1; i < (1 << n); i ++) {
      for(int j = 0; j < n; j ++) {
        if((1 << j) & i) {
          sum[i] = sum[i ^ (1 << j)] + a[j];
        }
      }
    }
    
    int ans = 0;
    for(int i = 1; i < (1 << n); i ++) {
      if(sum[i] < s) continue;
      
      int ok = 1;
      
      for(int j = 0; j < n; j ++) {
        if((1 << j) & i) {
          if(sum[i ^ (1 << j)] >= s) ok = 0;
        }
      }
      
      if(ok == 0) continue;
      int tmp = 0;
      for(int j = 0; j < n; j++) {
        if((1 << j) & i) tmp ++;
      }
      ans = max(ans, tmp);
    }
    printf("%d\n", ans);
  }
  return 0;
}

 

H - Bridges

求出割边,去掉割边,每个连通块缩点,会形成一棵树,看看树的直径,最优策略就是在直径两端添加边。

#include <bits/stdc++.h>
using namespace std;

const int N  = 2e5 + 10;
int dfn[N],low[N],dfs_clock;

int n, m;
int h[N], to[N], nx[N], sz;

int bridge[N];

int belong[N];
int block;

int p1, p2;
int dis1, dis2;
int f[N];

vector<int> g[N];

void add(int a, int b) {
  to[sz] = b;
  nx[sz] = h[a];
  h[a] = sz ++;
}

void tarjan(int u, int fa)
{
  dfn[u] = low[u] = ++dfs_clock;
  bool flag = false;
  for(int i=h[u]; i != -1; i = nx[i])
  {
    int v = to[i];
    if(v==fa && !flag)//如果有重边,那么边(u,v)被存了两次,所以,如果第二次访问,就让他通过
    {
      flag = true;
      continue;
    }
    if(dfn[v] == 0)
      tarjan(v,u);
    low[u] = min(low[u],low[v]);
    if(low[v] > dfn[u]) {
      //cntCut++;
      bridge[i] = 1;
    }
  }
}

void dfs(int x) {
  belong[x] = block;
  for(int i = h[x]; i != -1; i = nx[i]) {
    if(bridge[i]) continue;
    if(belong[to[i]]) continue;
    dfs(to[i]);
  }
}

void dfs1(int x, int y) {
  f[x] = 1;
  if(y > dis1) {
    dis1 = y;
    p1 = x;
  }
  for(int i = 0; i < g[x].size(); i ++) {
    if(f[g[x][i]]) continue;
    dfs1(g[x][i], y + 1);
  }
}

void dfs2(int x, int y) {
  f[x] = 1;
  if(y > dis2) {
    dis2 = y;
    p2 = x;
  }
  for(int i = 0; i < g[x].size(); i ++) {
    if(f[g[x][i]]) continue;
    dfs2(g[x][i], y + 1);
  }
}

int main()
{
  int T;
  scanf("%d", &T);
  while(T--) {
    scanf("%d%d",&n,&m);
    
    sz = 0;
    dfs_clock = 0;
    memset(dfn, 0, sizeof dfn);
    memset(low,0,sizeof low);
    
    for(int i = 0; i <= n; i ++) {
      h[i] = -1;
    }
    for(int i=0; i<m; ++i)
    {
      int a, b;
      scanf("%d%d",&a,&b);
      add(a, b);
      add(b, a);
    }
  
    memset(bridge, 0, sizeof bridge);
    tarjan(1, -1);
    for(int i = 0; i < sz; i ++) {
      if(bridge[i]) bridge[i ^ 1] = 1;
    }
    
    /*
    for(int from = 1; from <= n; from ++) {
      for(int i = h[from]; i != - 1; i = nx[i]) {
        if(bridge[i])
          printf("%d - %d\n", from, to[i]);
      }
    }
     */
    
    memset(belong,0,sizeof belong);
    block = 0;
    for(int i = 1; i <= n; i ++) {
      if(belong[i] == 0) {
        block ++;
        dfs(i);
      }
    }
    
    /*
    for(int i = 1; i <= n; i ++) {
      cout << i << " " << belong[i] << endl;
    }
     */
    
    for(int i = 1; i <= block; i ++) {
      g[i].clear();
    }
    
    for(int from = 1; from <= n; from ++) {
      for(int i = h[from]; i != - 1; i = nx[i]) {
        if(bridge[i]) {
       //   cout << belong[from] << " " << belong[to[i]] << endl;
          g[belong[from]].push_back(belong[to[i]]);
          g[belong[to[i]]].push_back(belong[from]);
        }
      }
    }
    
    memset(f,0,sizeof f);
    p1 = 0;
    dis1 = 0;
    dfs1(1, 0);
    
    memset(f,0,sizeof f);
    p2 = 0;
    dis2 = 0;
    dfs2(p1,0);
    
    printf("%d\n", block - 1 - dis2);
  }
  return 0;
}

 

I - Bahosain and Digits

枚举答案,以及枚举最终变到哪个数字,然后验证一下是否可行。

#include <bits/stdc++.h>
using namespace std;

int T;
char s[500];
int f[500], t[500], ci[500], sum[500];
int len;


int Get(int x) {
  if(x < 0) return 0;
  return sum[x];
}

int Sum(int L, int R) {
  return (Get(R) - Get(L - 1) + 10) % 10;
}

bool check(int x, int y) {
  for(int i = 0; i < len; i ++) {
    t[i] = f[i];
    ci[i] = 0;
    sum[i] = 0;
  }
  for(int i = 0; i <= len - x; i ++) {
    ci[i] = 0;
    t[i] = (t[i] + Sum(i-x+1,i-1)) % 10;
    while(t[i] != y) {
      t[i] = (t[i] + 1) % 10;
      ci[i] ++;
    }
    sum[i] = (Get(i - 1) + ci[i]) % 10;
  }
  for(int i = len - x + 1; i < len; i ++) {
    ci[i] = 0;
    t[i] = (t[i] + Sum(i-x+1,i-1)) % 10;
   // cout << i << " " << i-x+1 << " " << i-1 << endl;
    sum[i] = (Get(i - 1) + ci[i]) % 10;
  }
  
  for(int i = 0; i< len; i++) {
    if(t[i] != t[0]) return 0;
  }
  return 1;
}

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%s", s);
    len = strlen(s);
    for(int i = 0; s[i]; i ++) {
      f[i] = s[i] - '0';
    }
  
    int ans = 1;
    int ok = 0;
    for(int i = len; i >= 1; i --) {
      for(int limit = 0; limit <= 9; limit ++) {
        if(check(i, limit)) {
          ans = i;
          ok = 1;
          break;
        }
      }
      if(ok) break;
    }
    printf("%d\n", ans);
  }
  return 0;
}

 

J - Candy

贪心。人按年龄排序,糖果按个数排序,贪心拿就好了。

#include <bits/stdc++.h>
using namespace std;

int T;
int n, m;

int age[100010];
int tang[100010];

struct X {
  int x, y;
}s[100010], t[100010];

int sz1, sz2;

int main() {
  scanf("%d",&T);
  while(T--) {
    scanf("%d%d",&n, &m);
    for(int i = 1; i <= n; i ++) {
      scanf("%d", &age[i]);
    }
    sort(age + 1, age + 1 + n);
    
    for(int i = 1; i <= m; i ++) {
      scanf("%d", &tang[i]);
    }
    sort(tang+1, tang+1+m);
    
    sz1 = 0, sz2 = 0;
    
    s[sz1].x = age[1];
    s[sz1].y = 1;
    for(int i =2 ; i <= n;i ++) {
      if(age[i] != s[sz1].x) {
        sz1 ++;
        s[sz1].x = age[i];
        s[sz1].y = 1;
      } else {
        s[sz1].y ++;
      }
    }
    
    for(int i = 0; i <= sz1; i ++){
    //  cout << s[i].x << " " << s[i].y << endl;
    }
    
    t[sz2].x = tang[1];
    t[sz2].y = 1;
    for(int i = 2; i <= m; i ++) {
      if(tang[i] != t[sz2].x) {
        sz2 ++;
        t[sz2].x = tang[i];
        t[sz2].y = 1;
      } else {
        t[sz2].y ++;
      }
    }
    
    for(int i = 0; i <= sz2; i ++){
    //    cout << t[i].x << " " << t[i].y << endl;
    }
    
    
    int ok = 1;
    
    int p2 = 0;
    for(int i = 0; i <= sz1; i ++) {
      while(p2 <= sz2 && t[p2].y < s[i].y) {
        p2 ++;
      }
      if(p2 > sz2) {
        ok = 0;
        break;
      }
      p2 ++;
    }
    if(ok) printf("YES\n");
    else printf("NO\n");
  }
  return 0;
}

 

K - Runtime Error

枚举一下就好了,注意 $a_i$ 为 $0$ 的情况。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
int T;
int f[maxn];
int a[maxn];

int n,k;

int main() {
  scanf("%d", &T);
  while(T--) {
    memset(f, 0, sizeof f);
    scanf("%d%d", &n, &k);
    for(int i =1; i <= n; i ++) {
      scanf("%d", &a[i]);
      f[a[i]] ++;
    }
    
    sort(a+1,a+1+n);
    
    int ok = 0;
    for(int i =1 ; i <= n; i ++) {
      if(a[i] == 0) continue;
      if(k % a[i]) continue;
      if(a[i] != k / a[i]) {
        if(f[a[i]] && f[k / a[i]]) {
          printf("%d %d\n", a[i], k / a[i]);
          ok = 1;
          break;
        }
      } else {
        if(f[a[i]] >= 2) {
          printf("%d %d\n", a[i], k / a[i]);
          ok = 1;
          break;
        }
      }
    }
    
    if(ok == 0) printf("-1\n");
    
  }
  return 0;
}

 

L - Alternating Strings II

D题的加强版,可以发现能推到 $i$ 位置的是一段连续的区间,维护区间最小值即可。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
int T, n, k;
char s[maxn];

int seg[maxn * 4];
int pre[maxn];
int dp[maxn];
int len;

void update(int pos, int val, int l, int r, int rt) {
  if(l == r) {
    seg[rt] = val;
    return;
  }
  int mid = (l + r) / 2;
  if(pos <= mid) update(pos, val, l, mid, 2 * rt);
  else update(pos, val, mid + 1, r, 2 * rt + 1);
  seg[rt] = min(seg[2 * rt],seg[2 * rt + 1]);
}

int get(int L, int R, int l, int r, int rt) {
  if(L <= l && r <= R) {
    return seg[rt];
  }
  int left = 200000;
  int right = 200000;
  int mid = (l + r) / 2;
  if(L <= mid) left = get(L, R, l, mid, 2 * rt);
  if(R > mid) right = get(L, R, mid + 1, r, 2 * rt + 1);
  return min(left, right);
}

int Qu(int L, int R, int idx) {
  if(L < 0) return 0;
  return get(L, R, 0, len - 1, 1);
}

int main() {
  scanf("%d", &T);
  while(T--) {
    memset(pre, -1, sizeof pre);
    scanf("%d%d", &n, &k);
    scanf("%s", s);
    len = strlen(s);
    
    pre[0] = 0;
    for(int i = 1; i < len; i ++) {
      pre[i] = i;
      if(s[i] != s[i - 1]) pre[i] = pre[i - 1];
    }
    
    for(int i = 0; i < len; i ++) {
   //   cout << i << " " << pre[i] << endl;
    }
    
    dp[0] = 1;
    update(0, dp[0], 0, len - 1, 1);
    for(int i = 1; i < len; i ++) {
      dp[i] = dp[i - 1] + 1;
      if(i - pre[i] + 1 >= k) {
        
      } else {
        if(i - k >= -1) dp[i] = min(dp[i - 1], Qu(i - k, pre[i] - 2, i)) + 1;
        else if(pre[i] - 2 >= -1) dp[i] = 1;
        else dp[i] = dp[i - 1] + 1;
      }
      update(i, dp[i], 0, len - 1, 1);
    //  cout << i << " " << dp[i] << endl;
    }
    printf("%d\n", dp[len - 1] - 1);
  }
  return 0;
}

 

posted @ 2018-04-03 17:26  Fighting_Heart  阅读(786)  评论(0编辑  收藏  举报