zoukankan      html  css  js  c++  java
  • 2017 ACM Amman Collegiate Programming Contest 题解

    题目链接

    A - Watching TV

    模拟。统计一下哪个数字最多即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    
    int T, n;
    char s[maxn];
    int a[maxn];
    
    int main() {
      scanf("%d", &T);
      while(T --) {
        scanf("%d", &n);
        memset(a, 0, sizeof a);
        for(int i = 1; i <= n; i ++) {
          int x;
          scanf("%s%d", s, &x);
          a[x] ++;
        }
        int mx = 0;
        for(int i = 11111; i <= 99999; i ++) {
          mx = max(mx, a[i]);
        }
        for(int i = 11111; i <= 99999; i ++) {
          if(a[i] == mx) {
            printf("%d
    ", i);
            break;
          }
        }
      }
      return 0;
    }
    

    B - Longest Prefix

    模拟。一个串能乱变,一个串不能动,只要统计能变的那个串每个字母有几个即可,到不能动的串上来消耗。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    
    int T, n;
    char s[maxn], t[maxn];
    int cnt[500];
    
    int main() {
      scanf("%d", &T);
      while(T --) {
        memset(cnt, 0, sizeof cnt);
        scanf("%s%s", s, t);
        int lens = strlen(s);
        int lent = strlen(t);
        
        for(int i = 0; t[i]; i ++) {
          cnt[t[i]] ++;
        }
        
        int ans = -1;
        for(int i = 0; i < lens; i ++) {
          if(cnt[s[i]] == 0) break;
          ans = i;
          cnt[s[i]] --;
        }
        printf("%d
    ", ans + 1);
        
      }
      return 0;
    }
    

    C - Lunch Break

    水题。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    
    int T, n;
    int a, b, c;
    
    int main() {
      scanf("%d", &T);
      while(T --) {
        scanf("%d%d%d", &a, &b, &c);
        if(a < b && a < c) {
          printf("First
    ");
        }
        if(b < a && b < c) {
          printf("Second
    ");
        }
        if(c < a && c < b) {
          printf("Third
    ");
        }
        
      }
      return 0;
    }
    

    D - Counting Paths

    组合数。通过分析可以发现答案为$2*C_{n - 1}^m$。

    #include <iostream>
    #include <string.h>
    #include <stdio.h>
    
    using namespace std;
    typedef long long LL;
    
    LL n,m;
    LL p = 1e9 + 7;
    
    const int maxn = 1e5 + 10;
    LL f[maxn];
    
    //******************************
    //返回d=gcd(a,b);和对应于等式ax+by=d中的x,y
    long long extend_gcd(long long a,long long b,long long &x,long long &y)
    {
      if(a==0&&b==0) return -1;//无最大公约数
      if(b==0){x=1;y=0;return a;}
      long long d=extend_gcd(b,a%b,y,x);
      y-=a/b*x;
      return d;
    }
    //*********求逆元素*******************
    //ax = 1(mod n)
    long long mod_reverse(long long a,long long n)
    {
      long long x,y;
      long long d=extend_gcd(a,n,x,y);
      if(d==1) return (x%n+n)%n;
      else return -1;
    }
    
    
    LL C(LL n, LL m)
    {
      long long A = f[n];
      long long B = f[n - m] * f[m] % p;
      long long C = mod_reverse(B, p);
      return A * C % p;
    }
    
    int main()
    {
      int T;
      f[0] = 1;
      for(long long i = 1; i < maxn; i ++) {
        f[i] = f[i - 1] * i % p;
      }
      scanf("%d", &T);
      while(T--)
      {
        scanf("%lld%lld", &n, &m);
        if(n == 0) {
          printf("0
    ");
          continue;
        }
        printf("%lld
    ", C(n - 1, m) * 2 % p);
      }
      return 0;
    }
    

    E - Car Factory

    水题。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    
    int T, n;
    char s[maxn], t[maxn];
    int cnt[500];
    
    int main() {
      scanf("%d", &T);
      while(T --) {
        long long a, b;
        cin >> a >> b;
        cout << a + b - 1 << endl;
        
      }
      return 0;
    }
    

    F - Cooking Time

    贪心,线段树。如果满了,每次应该扔掉最晚用的那个。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    int T, n, k;
    int a[maxn], b[maxn], nx[maxn], pos[maxn];
    int s[4 * maxn];
    int f[maxn];
    
    int lsh(int x) {
      int L = 1, R = n;
      while(L <= R) {
        int mid = (L + R) / 2;
        if(b[mid] > x) R = mid - 1;
        else if(b[mid] < x) L = mid + 1;
        else return mid;
      }
      return 0;
    }
    
    void build(int l, int r, int rt) {
      s[rt] = 0;
      if(l == r) return;
      int mid = (l + r) / 2;
      build(l, mid, 2 * rt);
      build(mid + 1, r, 2 * rt + 1);
    }
    
    void update(int p, int val, int l, int r, int rt) {
      if(l == r) {
        s[rt] = val;
        return;
      }
      int mid = (l + r) / 2;
      if(p <= mid) update(p, val, l, mid, 2 * rt);
      else update(p, val, mid + 1, r, 2 * rt + 1);
      s[rt] = max(s[2 * rt], s[2 * rt + 1]);
    }
    
    int work(int l, int r, int rt) {
      if(l == r) return l;
      int mid = (l + r) / 2;
      if(s[2 * rt] > s[2 * rt + 1]) return work(l, mid, 2 * rt);
      else return work(mid + 1, r, 2 * rt + 1);
    }
    
    int main() {
      scanf("%d", &T);
      while(T --) {
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; i ++) {
          scanf("%d", &a[i]);
          b[i] = a[i];
          f[i] = 0;
          pos[i] = n + 1;
        }
        sort(b + 1, b + 1 + n);
        for(int i = 1; i <= n; i ++) {
          a[i] = lsh(a[i]);
        }
        for(int i = n; i >= 1; i --) {
          nx[i] = pos[a[i]];
          pos[a[i]] = i;
        }
        build(1, n, 1);
        int ans = 0;
        int now = 0;
        for(int i = 1; i <= n; i ++) {
          if(f[a[i]]) {
            update(a[i], nx[i], 1, n, 1);
            continue;
          }
          ans ++;
          if(now < k) {
            f[a[i]] = 1;
            now ++;
            update(a[i], nx[i], 1, n, 1);
          } else {
            int del = work(1, n, 1);
            update(del, 0, 1, n, 1);
            update(a[i], nx[i], 1, n, 1);
            f[del] = 0;
            f[a[i]] = 1;
          }
        }
        printf("%d
    ", ans);
      }
      return 0;
    }
    

    G - Super Subarray

    区间和要能被区间内每个数都整除,就是区间和要能被区间的最小公倍数整除,因此处理出区间的和以及最小公倍数即可,注意爆long long。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 2000 + 10;
    int T;
    int n, k;
    long long a[maxn];
    long long sum[maxn][maxn];
    long long lcm[maxn][maxn];
    long long limit = 2000LL * 1e9;
    
    long long gcd(long long a, long long b) {
      if(b == 0) return a;
      return gcd(b, a % b);
    }
    
    long long LCM(long long a, long long b) {
      long long A = a / gcd(a, b);
      long long B = b;
      
      if(A > limit / B) return -1;
      return A * B;
    }
    
    int main() {
      scanf("%d", &T);
      while(T --) {
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++) {
          scanf("%lld", &a[i]);
        }
        int ans = 0;
        for(int i = 1; i <= n; i ++) {
          for(int j = i; j <= n; j ++) {
            sum[i][j] = sum[i][j - 1] + a[j];
            if(j == i) lcm[i][j] = a[j];
            else lcm[i][j] = LCM(a[j], lcm[i][j - 1]);
            if(lcm[i][j] > limit || lcm[i][j] == -1) break;
            if(sum[i][j] % lcm[i][j] == 0) ans ++;
          }
        }
        printf("%d
    ", ans);
      }
      return 0;
    }
    

    H - Palindrome Number

    构造。主要思想是能放$9$就一直放$9$,不能放$9$就放剩余的那个数,注意判断一下不存在的情况。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e6 + 10;
    int T;
    int n, s;
    int ans[maxn];
    
    int main() {
      scanf("%d", &T);
      while(T --) {
        scanf("%d%d", &n, &s);
        if(n % 2 == 0) {
          if(s % 2 || s > n * 9) printf("-1
    ");
          else {
            s = s / 2;
            for(int i = 0; i < n / 2; i ++) {
              if(s >= 9) ans[i] = 9, s -= 9;
              else ans[i] = s, s = 0;
            }
            for(int i = 0; i < n / 2; i ++) {
              printf("%d", ans[i]);
            }
            for(int i = n / 2 - 1; i >= 0; i --) {
              printf("%d", ans[i]);
            }
            printf("
    ");
          }
        } else {
          int p = -1;
          for(int i = 0; i <= 9; i ++) {
            if((s - i) % 2 != 0) continue;
            if((s - i) > 9 * (n - 1)) continue;
            p = i;
            break;
          }
          if(p == -1) {
            printf("-1
    ");
            continue;
          }
          s = (s - p) / 2;
          for(int i = 0; i < n / 2; i ++) {
            if(s >= 9) ans[i] = 9, s -= 9;
            else ans[i] = s, s = 0;
          }
          if(ans[0] == 0) {
            printf("-1
    ");
            continue;
          }
          for(int i = 0; i < n / 2; i ++) {
            printf("%d", ans[i]);
          }
          printf("%d", p);
          for(int i = n / 2 - 1; i >= 0; i --) {
            printf("%d", ans[i]);
          }
          printf("
    ");
        }
      }
      return 0;
    }
    

    I - Rock Piles

    规律。$dp$打表找一下规律就可以了。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    
    int T, n, m;
    int dp[1010][1010];
    
    void init() {
      for(int i = 0; i <= 1000; i ++) {
        dp[0][i] = i % 2;
        dp[i][0] = i % 2;
      }
      for(int i = 1; i <= 1000; i ++) {
        for(int j = i; j <= 1000; j ++) {
          if(dp[i - 1][j] == 0
             || dp[i][j - 1] == 0
             || dp[i - 1][j - 1] == 0) {
            dp[i][j] = 1;
            dp[j][i] = 1;
          } else {
            dp[i][j] = 0;
            dp[j][i] = 0;
          }
        }
      }
      for(int i = 0; i <= 10; i ++) {
        for(int j = i; j <= 10; j ++) {
          printf("%d %d %d
    ", i, j, dp[i][j]);
        }
      }
    }
    
    int main() {
     // init();
      scanf("%d", &T);
      while(T --) {
        int ans;
        scanf("%d%d", &n, &m);
        if(n > m) swap(n, m);
        if(n % 2) ans = 1;
        else ans = m % 2;
        if(ans) printf("hasan
    ");
        else printf("abdullah
    ");
      }
      return 0;
    }
    

    J - Spilt the String

    暴力。暴力枚举长度,然后验证一下即可。复杂度大约是$O(n*ln(n))$。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5 + 10;
    int T;
    char s[maxn];
    int a[maxn];
    int L, R;
    
    int work(int x) {
      int now;
      for(now = L + x; now <= R; now += x) {
        if(now > R + 1) return 0;
        if(now == R + 1) return 1;
        if(a[now - 1] == 1 && a[now] == 0) {
          while(a[now] == 0) now ++;
        }
        else return 0;
      }
      if(now != R + 1) return 0;
      return 1;
    }
    
    int main() {
      scanf("%d", &T);
      getchar();
      while(T --) {
        gets(s);
        int len = strlen(s);
        for(int i = 0; i < len; i ++) {
          if(s[i] == ' ') a[i] = 0;
          else a[i] = 1;
        }
        L = 0, R = len - 1;
        while(a[L] == 0) L ++;
        while(a[R] == 0) R --;
        //printf("%d %d
    ", L, R);
        if(R < L) {
          while(1) {}
          printf("YES
    ");
          continue;
        }
        int ans = 0;
        for(int i = 1; i < len; i ++) {
          ans = work(i);
        //  if(ans) printf("debug %d
    ", i);
          if(ans) break;
        }
        if(ans) printf("YES
    ");
        else printf("NO
    ");
      }
      return 0;
    }
    

    K - Two Subarrays

    $dp$。枚举$i$位置作为分割,那么答案可能是$[1,i]$中的最大值减去$[i + 1,n]$的最小值,也可以反过来。类似于最大子串和的思路可以搞定。

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

    L - The Shortest Path

    $spfa$。某点入队超过$n$次就表示存在负环。某点最短路小于图中所有负边权之和,也说明存在负环。

    #include <bits/stdc++.h>
    using namespace std;
    
    const long long INF = 1LL * 6000 * 1e6;
    const int maxn = 1e5 + 10;
    int T, n, m;
    int h[maxn], v[maxn], nx[maxn];
    long long w[maxn];
    int sz;
    long long dis[maxn];
    int f[maxn], cnt[maxn];
    long long g[2100][2100];
    long long sum;
    long long ans;
    
    void add(int a, int b, long long c) {
      v[sz] = b;
      w[sz] = c;
      nx[sz] = h[a];
      h[a] = sz ++;
    }
    
    void spfa() {
      int fail = 0;
      for(int i = 0; i <= n; i ++) {
        dis[i] = INF;
        f[i] = 0;
        cnt[i] = 0;
      }
      queue<int> q;
      dis[0] = 0;
      f[0] = 1;
      q.push(0);
      while(!q.empty()) {
        int first = q.front();
        q.pop();
        f[first] = 0;
        cnt[first] ++;
        if(cnt[first] == n + 1) {
          fail = 1;
          break;
        }
        if(dis[first] < sum) {
          fail = 1;
          break;
        }
        for(int i = h[first]; i != -1; i = nx[i]) {
          if(dis[first] + w[i] < dis[v[i]]) {
            dis[v[i]] = dis[first] + w[i];
            if(f[v[i]] == 0) {
              f[v[i]] = 1;
              q.push(v[i]);
            }
          }
        }
      }
      if(fail) {
        printf("-inf
    ");
      } else {
        long long mn = INF;
        for(int i = 1; i <= n; i ++) {
          mn = min(mn, dis[i]);
        }
        if(mn == 0) printf("%lld
    ", ans);
        else printf("%lld
    ", min(ans, mn));
      }
    }
    
    int main() {
      scanf("%d", &T);
      while(T --) {
        scanf("%d%d", &n, &m);
        for(int i = 0; i <= n; i ++) {
          h[i] = -1;
        }
        sz = 0;
        for(int i = 0; i <= n; i ++) {
          for(int j = 0; j <= n; j ++) {
            g[i][j] = INF;
          }
        }
        for(int i = 1; i <= m; i ++) {
          int a, b;
          long long c;
          scanf("%d%d%lld", &a, &b, &c);
          g[a][b] = min(c, g[a][b]);
        }
        sum = 0;
        ans = INF;
        for(int i = 1; i <= n; i ++) {
          for(int j = 1; j <= n; j ++) {
            if(g[i][j] == INF) continue;
            add(i, j, g[i][j]);
            ans = min(ans, g[i][j]);
            if(g[i][j] < 0) sum += g[i][j];
          }
        }
        for(int i = 1; i <= n; i ++) {
          add(0, i, 0);
        }
        spfa();
      }
      return 0;
    }
    

    M - Restore Points

    暴力。将$d$数组排序,那么最右边的那个点的坐标肯定是$d$数组最后一个值,然后枚举$d$数组倒数第二个值是放在靠左还是靠右,一直枚举下去即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e6 + 10;
    int T, n, m;
    int d[maxn];
    int ans[maxn];
    int p[maxn];
    int suc;
    
    void dfs(int x, int y) {
      if(x == n) {
        int ok = 1;
        for(int i = 0; i < m; i ++) {
          if(p[d[i]]) ok = 0;
        }
        if(ok) suc = 1;
        return;
      }
      if(p[d[y]] == 0) {
        dfs(x, y - 1);
        return;
      }
      for(int t = 0; t < 2; t ++) {
        int fail = 0;
        if(t == 0) ans[x] = d[y];
        else ans[x] = ans[1] - d[y];
        for(int i = 0; i < x; i ++) {
          if(p[abs(ans[x] - ans[i])] == 0) {
            fail = 1;
          }
        }
        if(fail) continue;
        for(int i = 0; i < x; i ++) {
          p[abs(ans[x] - ans[i])] --;
        }
        dfs(x + 1, y - 1);
        if(suc) return;
        for(int i = 0; i < x; i ++) {
          p[abs(ans[x] - ans[i])] ++;
        }
      }
    }
    
    int main() {
      scanf("%d", &T);
      while(T --) {
        scanf("%d", &n);
        m = n * (n - 1) / 2;
        for(int i = 0; i < m; i ++) {
          scanf("%d", &d[i]);
          p[d[i]] ++;
        }
        sort(d, d + m);
        ans[0] = 0;
        ans[1] = d[m - 1];
        p[ans[1]] --;
        suc = 0;
        dfs(2, m - 2);
        sort(ans, ans + n);
        for(int i = 0; i < n; i ++) {
          printf("%d", ans[i]);
          if(i < n - 1) printf(" ");
          else printf("
    ");
        }
        for(int i = 0; i < m; i ++) {
          if(p[d[i]]) {
            while(1) {}
          }
        }
      }
      return 0;
    }
    
  • 相关阅读:
    IPC---信号量
    static的用法
    模拟对话框的实现
    Dom选择器使用与调试记录
    第一个javascript脚本
    javascript基础总汇
    overflow的量两种模式
    固定标签到页面
    固定标签到某个标签
    固定标签(position: fixed)
  • 原文地址:https://www.cnblogs.com/zufezzt/p/8404115.html
Copyright © 2011-2022 走看看