• [NOI2018]屠龙勇士


    嘟嘟嘟


    今天复习一下excrt,还算是没忘。


    这道题,首先用set预处理一下,找到斩杀每条龙用哪把刀。
    然后能列出方程(ATK_i * x - p_i y = a_i)。这显然是一个不定方程,用exgcd搞一下就行。然后我就想,怎么把所有解合并。假设一个特解是(x'),那么通解就是(x = x' + k * frac{p_i}{gcd(ATK_i, p_i)}),就可以写成(x equiv x' (mod frac{p_i}{(ATK_i, p_i)}))。然后这一堆就可以用excrt搞了。
    看数据范围,会发现有些坑点,就是存在(a_i > p_i)的情况。这会导致你把巨龙的血耗到大于0的情况,却刚好是(p_i)的倍数,这显然是杀不死龙的。但在excrt中这是一个合法解。
    然而所有这些情况,都满足(p_i = 1),那么答案就是(max_{i = 1} ^ {n} lceil frac{a_i}{ATK_i} ceil)


    最后因为不会用set,把s.upper_bound(a[i])写成了upper_bound(s.begin(), s.end(), a[i]),后面点全TLE了,而前面的点竟然还能A。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e5 + 5;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    int n, m;
    ll a[maxn], p[maxn], t[maxn], atk[maxn];
    multiset<ll> s;
    
    In void work0()
    {
      ll ans = 0;
      for(int i = 1; i <= n; ++i) ans = max(ans, (a[i] + atk[i] - 1) / atk[i]);
      write(ans), enter;
    }
    
    #define snew multiset<ll>::iterator
    snew it;
    In bool init()
    {
      for(int i = 1; i <= n; ++i)
        {
          it = s.begin();
          if(*it > a[i]) atk[i] = *it, s.erase(it);
          else
    	{
    	  it = s.upper_bound(a[i]), --it;
    	  atk[i] = *it, s.erase(it);
    	}
          s.insert(t[i]);
        }
      for(int i = 1; i <= n; ++i) if(a[i] > p[i]) {work0(); return 1;}
      return 0;
    }
    
    ll A[maxn], B[maxn];
    In ll mul(ll a, ll b, ll mod)
    {
      ll d = (long double) a / mod * b + 1e-8;
      ll ret = a * b - d * mod;
      return ret < 0 ? ret + mod : ret;
    }
    In void exgcd(ll a, ll b, ll& x, ll& y, ll& d)
    {
      if(!b) d = a, x = 1, y = 0;
      else exgcd(b, a % b, y, x, d), y -= a / b * x;
    }
    In bool solve()
    {
      for(int i = 1; i <= n; ++i)
        {
          ll x, y, d;
          exgcd(atk[i], p[i], x, y, d);
          if(a[i] % d) return 0;
          ll tp = p[i] / d;
          x = mul((x % tp + tp) % tp, a[i] / d, tp);
          A[i] = x, B[i] = tp;
        }
      return 1;
    }
    
    In ll excrt()
    {
      ll ans = A[1], M = B[1];
      for(int i = 1; i <= n; ++i)
        {
          ll x, y, d, c = ((A[i] - ans) % B[i] + B[i]) % B[i];
          exgcd(M, B[i], x, y, d);
          if(c % d) return -1;
          ll tp = B[i] / d;
          x = mul((x % tp + tp) % tp, c / d, tp);
          ans += x * M, M *= tp, ans %= M;
        }
      return ans;
    }
    
    int main()
    {
      int T = read();
      while(T--)
        {
          n = read(), m = read();
          s.clear();
          for(int i = 1; i <= n; ++i) a[i] = read();
          for(int i = 1; i <= n; ++i) p[i] = read();
          for(int i = 1; i <= n; ++i) t[i] = read();
          for(int i = 1, x; i <= m; ++i) x = read(), s.insert(x);
          if(init()) continue;
          write(solve() ? excrt() : -1), enter;
        }
      return 0;
    }
    
  • 相关阅读:
    for循环里面不要进行remove操作,for循环里remove元素后,list的下标会减小,导致遍历不完全
    elasticsearch,java api, transport Client, 查询时索引库可以用通配符*和删除接口不能用
    (一)WebPack4.0 从零开始
    合并代码 dev 到 master
    vscode 终端无法输入问题 看这个就行了
    node 学习笔记:一、 nvm 安装管理Node版本
    常见的对象创建模式
    深入理解闭包
    sort对数组排序
    图片压缩
  • 原文地址:https://www.cnblogs.com/mrclr/p/10407101.html
Copyright © 2020-2023  润新知