P4774 [NOI2018] 屠龙勇士
P4774 [NOI2018] 屠龙勇士
太毒瘤了,一眼模拟,二眼ExCRT板子,马上去写,发现不对劲,思路在代码里十分清晰,且看
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e5+10;
int t,n,m,a[maxn],p[maxn],init,killget[maxn];
int X,Y,g,a_,b_,mx;//a_存总mod;b_存总c
multiset<int>s;
void exgcd(int a,int b){
if(!b){X=1,Y=0,g=a;return;}
exgcd(b,a%b);
int T=X;
X=Y;Y=T-(a/b)*X;
}
int mul(int A,int B,int mod){//龟速乘 防爆longlong
int res=0;
A=(A%mod+mod)%mod,B=(B%mod+mod)%mod;
while(B){
if(B&1)res=(res+A)%mod;
B>>=1;
A=A*2%mod;
}return (res%mod+mod)%mod;
}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>t;
E:while(t--){
a_=1,b_=0;mx=0;s.clear();
//c ax+by=c; mx max(a/k向上); m mod
cin>>n>>m;
for(int i=1;i<=n;++i)cin>>a[i];//生命
for(int i=1;i<=n;++i)cin>>p[i];//回复
for(int i=1;i<=n;++i)cin>>killget[i];//杀死得到剑
for(int i=1;i<=m;++i)cin>>init,s.insert(init);//初始剑
for(int i=1;i<=n;++i){
auto it=s.upper_bound(a[i]);//大于当前 --it 为不大于
if(it!=s.begin())it--;//没得选不减
int k=*it;s.erase(it);s.insert(killget[i]);
/*
对于新一组方程a[i]+p[i]y=kx
考虑通过exgcd x=x'+k't去除x系数k
a[i] ≡kx (mod p[i]) 解exgcd
标准式子 ax*(c/g)+by*(c/g)=c 此处需判断c%g
特解x' 通解x=(a[i]/g)*x'+(p[i]/g)*t t任取
系数化为一 x ≡(a[i]/g)*x' (mod p[i]/g)
*/
mx=max(mx,(a[i]-1)/k+1);
k%=p[i],a[i]%=p[i];
if(!k&&a[i]){cout<<-1<<"\n";goto E;}
if(!k&&!a[i])continue;
exgcd(k,p[i]);
if(a[i]%g){cout<<-1<<"\n";goto E;}
p[i]=p[i]/g;
a[i]=mul(a[i]/g,X,p[i]);
/*
同余方程来力
形式为 x ≡b (mod a)
考虑与初始方程合并
初始方程: x ≡0 (mod 1)
即 a_=1 b_=0
merge(a_,b_,p[i],a[i]);
ExCRT启动
*/
exgcd(a_,p[i]);
if((a[i]-b_)%g){puts("-1");goto E;}
int t0=mul(X,(a[i]-b_)/g,(p[i]/g)),m=lcm(a_,p[i]);
b_=(mul(t0,a_,m)+b_)%m;
a_=m;
// cout<<mx<<"\n";
}
/*
注意 每一个新方程的需满足kx>=a[i] x>=(a[i]-1)/k+1;(向下取整)
最后所求同余方程解x在b_ 特判(补齐)即可 mx存 最大(a[i]-1)/k+1
*/
cout<<(b_>=mx?b_:b_+(mx-b_-1)/a_*a_+1)<<'\n';
}
return 0;
}

浙公网安备 33010602011771号