扩展欧几里德 | CodeForces 898B, CodeForces 599B



前言

最近课业繁重 + 养病就一直没时间和精力更新,个人觉得那些没有标明是水题的和我自己不会做的是有价值看的题,至于水题嘛连我自己都觉得水就别说各位大佬了
然后以后的刷题记会针对某一算法来展开,单纯训练思维的题目会减少
然后这个系列呢, 立个flag, 至少30篇

会做的题:

  1. (水题)Spotlights | CodeForces - 729B
    http://codeforces.com/problemset/problem/729/B
  2. (水题)Tea Party | CodeForces - 808C
    http://codeforces.com/problemset/problem/808/C
  3. (水题)Polo the Penguin and Strings | CodeForces - 289C
    http://codeforces.com/problemset/problem/289/C
  4. (水题)Increase and Decrease | CodeForces - 246B
    http://codeforces.com/problemset/problem/246/B
  5. (水题)Pocket Book | CodeForces - 152C
    http://codeforces.com/problemset/problem/152/C
  6. (水题)Dishonest Sellers | CodeForces - 779C
    http://codeforces.com/problemset/problem/779/C
  7. (水题)Div. 64 | CodeForces - 887A
    http://codeforces.com/problemset/problem/887/A
  8. Spongebob and Joke | CodeForces - 599B
    http://codeforces.com/problemset/problem/599/B
  9. Slava and tanks | CodeForces - 877C
    http://codeforces.com/problemset/problem/877/C
  10. Proper Nutrition | CodeForces - 898B
    http://codeforces.com/problemset/problem/898/B
  11. Chloe and the sequence | CodeForces - 743B
    http://codeforces.com/problemset/problem/743/B

不会做的题:

  1. Timofey and rectangles | CodeForces - 763B
    http://codeforces.com/problemset/problem/763/B
  2. New Year Book Reading | CodeForces - 500C
    http://codeforces.com/problemset/problem/500/C
  3. Bug in Code | CodeForces - 421D
    http://codeforces.com/problemset/problem/421/D
  4. Game of the Rows | CodeForces - 839B
    http://codeforces.com/problemset/problem/839/B


Proper Nutrition | CodeForces - 898B

题目大意
对于方程 ax + by = n,给定a,b,n, 求非负的x,y满足该式,无法求解输出”NO”

思路
第一种方法: 暴力(耗时140ms)
显而易见,从0开始枚举x,使得(n - a*x)%b == 0成立,到ax > n时结束枚举

  #include <iostream>
  #include <cstdio>
  #include <algorithm>
  using namespace std;
  typedef long long ll;

  int main(){
      ll n, a, b;
      while(cin >> n >> a >> b){
          ll x = -1, y = -1;
          for(ll i = 0; n - a*i >= 0; i++){
              if((n - a*i)%b == 0){
                  x = i;
                  y = (n - a*i)/b;
              }
          }
          if(x == -1 && y == -1){
              printf("NO\n");
          }else{
              printf("YES\n");
              printf("%lld %lld\n", x, y);
          }
      }
      return 0;
  }


第二种方法: 扩展欧几里德(耗时15ms)
没错如果只是暴力我绝对不会写题解的!
ax+by=c是标准的不定方程,可用扩展欧几里德求解,不懂扩展欧几里德算法的同学可以百度了解一下
用扩展欧几里德解不定方程我这也是第一次呢 :)

  #include <cstdio>
  #include <algorithm>
  using namespace std;
  typedef long long ll;

  ll exgcd(ll a, ll b, ll& x, ll& y){
      ll d = a;
      if(b == 0){
          x = 1, y = 0;
      }else{
          d = exgcd(b, a%b, y, x);    // x' = y;
          y -= a/b*x;                 // y' = x - a/b*y;
      }
      return d;
  }

  int main(){
      ll n, a, b, x, y, tmp;
      while(~scanf("%lld%lld%lld", &n, &a, &b)){
          tmp = __gcd(a, b);
          if(n % tmp != 0){         //a,b,c一定都能除以gcd(a,b),不能除必定无解
              printf("NO\n");
          }else{
              a /= tmp;
              b /= tmp;
              n /= tmp;             //以上三步将方程化为 a‘x + b'y = c'  
              exgcd(a, b, x, y);    //求解的是   a'x + b'y = 1  
              x = x*n;              //因为求解相差c'倍所以乘上c'  
              x = (x%b + b)%b;      //x可能为负数所以不断加上b  
              y = (n - a*x)/b;      //再用新的x求解出y  
              if(y < 0){            //x是非负最小解,对于这个解y还是负数那就没解了  
                  printf("NO\n");
              }else{
                  printf("YES\n");
                  printf("%lld %lld\n", x, y);
              }
          }
      }
      return 0;
}


Spongebob and Joke | CodeForces - 599B

题目大意
对于方程 b(i) = f(a(i)), 给定b(i), f(i)序列求解整个a(i)序列, 如果无法求解输出“Impossible”, 有多种结果输出”Ambiguity”

思路
用数学的方法分析这一题目, 方程左右两端再加个f^(-1), 可得 f^(-1)(b(i)) = a(i), 这样子所给条件就能直接求出b(i)
这个f^(-1)是什么呢,原来f(i)是下标对应值, 那么现在f^(-1)是值对应下标,仅此而已
因此 Impossible就是f^(-1)(b(i))无对应下标, Ambiguity就是f^(-1)(b(i))有多个下标对应
用两个数组或者map存b(i)和f^(-1)就可以把整道题写出来了
另外注意 Impossible 和 Ambiguity同时成立要先输出 Impossible, 不然会WA的 T_T

  #include <iostream>
  #include <algorithm>
  #include <cstring>
  #include <map>
  using namespace std;
  typedef long long ll;

  int cnt[N];
  map<int, int> mp_f; //f^(-1)(i)
  int arr[N];         //b(i)
  int ans[N];         //a(i)
  int ans_end;

  string res(int m){
      for(int i = 1; i <= m; i++){
          if(cnt[arr[i]] == 0)     return "Impossible";
      }
      for(int i = 1; i <= m; i++){
          if(cnt[arr[i]] >= 2)     return "Ambiguity";
          ans[i] = mp_f[arr[i]];
      }
      return "Possible";
  }

  int main(){
      ios::sync_with_stdio(false);
      int n, m;
      while(cin >> n >> m){
          memset(cnt, 0, sizeof(cnt));
          for(int i = 1; i <= n; i++){
              int tmp;
              cin >> tmp;
              mp_f[tmp] = i;        //值对应下标,存入f^(-1)
              cnt[tmp]++;           //统计值对应多个下标的可能性
              if(cnt[tmp] == 1){
                  mp_f.insert(pii(tmp, i));
              }
          }
          for(int i = 1; i <= m; i++){
              cin >> arr[i];
          }
          string str = res(m);
          cout << str << endl;
          if(str != "Possible")       continue;
          for(int i = 1; i <= m; i++){
              cout << ans[i];
              if(i < m)     cout << " ";
          }
          cout << endl;
      }
      return 0;
  }