[NOI2018] 屠龙勇士
作者:互联网
前言
属实是板题了,竟然没做过,本想rush一波结果怎么都过不了样例,然后去模板那里测发现也过不了样例,看半天原来是板子写挂了,相当尴尬。
题目
讲解
由于 ≡
打着太麻烦,所以下文直接用 =
了。
可以发现每头龙对应的剑是唯一确定的,所以用 \(\operatorname{multiset}\) 直接求出所有龙对应的剑,记其攻击力为 \(A_i\)。
然后我们观察一下数据范围,当不满足 \(a_i\le p_i\) 时,一定有 \(p_i=1\),此时答案为 \(\max\{\lceil\frac{a_i}{A_i}\rceil\}\),至于为什么出题人这么设计,我们接下来马上解答。
现在考虑 \(a_i\le p_i\) 的情况,我们其实是要求方程组 \(A_iX=a_i\pmod {p_i}\) 的解,可以发现这个方程对这道题成立的条件正是 \(a_i\le p_i\),或者说是 \(a_i<p_i\),因为初始血量 \(a_i\) 是不能凭空减少的,所以要求 \(a_i<p_i\),在这道题里面 \(a_i=p_i\) 的情况还要特判(但是数据太水不特判也能过)。
对于方程组 \(A_iX=a_i\pmod{p_i}\) 我们能很快想到扩展中国剩余定理,但是随即又想到它只能处理 \(X\) 前面没有系数的情况,那可怎么办呢?显然不能直接把 \(A_i\) 除到右边去,因为 \(A_i\) 在 \(\mod p_i\) 下未必有逆元。
把这个式子写成一般形式:\(p_it-A_iX=\gcd(p_i,A_i)\),用扩欧求出特解 \(t',X'\) 之后,我们就可以得到 \(X\) 的通解了:\(X=X'+k\times \frac{p_i}{\gcd(p_i,A_i)}\)
原式子的通解 \(X=X'\times \frac{a_i}{\gcd(p_i,A_i)}+k\times \frac{p_i}{\gcd(p_i,A_i)}\)
换成同余方程就是 \(X=X'\times \frac{a_i}{\gcd(p_i,A_i)}\pmod {\frac{p_i}{\gcd(p_i,A_i)}}\)
然后用扩展中国剩余定理合并即可。
代码
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;
typedef long long LL;
const int MAXN = 100005;
int n,m;
LL a[MAXN],p[MAXN],aw[MAXN],A[MAXN],r[MAXN];
multiset<LL> s;
LL Read()
{
LL x = 0,f = 1;char c = getchar();
while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
TT void Put1(T x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}
LL gsc(const LL x,const LL y,const LL MOD)
{
LL ret = x*y - (LL)((long double)x/MOD*y+0.5)*MOD;
return (ret%MOD+MOD)%MOD;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b) {x = 1;y = 0;return a;}
LL ret = exgcd(b,a%b,y,x);
y -= a/b*x; return ret;
}
int main()
{
// freopen("dragon.in","r",stdin);
// freopen("dragon.out","w",stdout);
for(int T = Read(); T ;-- T)
{
bool sp = 1; s.clear();
n = Read(); m = Read();
for(int i = 1;i <= n;++ i) a[i] = Read();
for(int i = 1;i <= n;++ i) p[i] = Read(),sp &= p[i] == 1;
for(int i = 1;i <= n;++ i) aw[i] = Read();
for(int i = 1;i <= m;++ i) s.insert(Read());
for(int i = 1;i <= n;++ i)
{
auto it = s.upper_bound(a[i]);
if(it != s.begin()) --it;
A[i] = *it; s.erase(it);
s.insert(aw[i]);
}
if(sp)
{
LL ans = 0;
for(int i = 1;i <= n;++ i) ans = Max(ans,(a[i]+A[i]-1)/A[i]);
Put(ans,'\n');
}
else
{
bool gg = 0;//G!
for(int i = 1;i <= n;++ i)
{
LL x,y,d; d = exgcd(p[i],A[i],x,y); p[i] /= d; A[i] /= d;
if(a[i] % d) {gg = 1;break;} a[i] /= d;
r[i] = gsc(y,a[i],p[i]);
}
for(int i = 1;i < n && !gg;++ i)
{
if(r[i] > r[i+1]) swap(r[i],r[i+1]),swap(p[i],p[i+1]);
LL x,y,d,cha = r[i+1]-r[i]; d = exgcd(p[i],p[i+1],x,y);
if(cha % d) {gg = 1;break;}
//p1x-p2y=r2-r1
p[i+1] = p[i] / d * p[i+1]; x = gsc(x,cha/d,p[i+1]);
r[i+1] = (r[i] + gsc(x,p[i],p[i+1])) % p[i+1];
}
if(gg) {Put(-1,'\n');continue;}
Put(r[n]>0?r[n] : p[n],'\n');
}
}
return 0;
}
标签:return,gcd,NOI2018,LL,MAXN,frac,屠龙,勇士,MOD 来源: https://www.cnblogs.com/PPLPPL/p/15851074.html