[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} \rceil\)


最后因为不会用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;
}
posted @ 2019-02-20 15:53  mrclr  阅读(173)  评论(0编辑  收藏  举报