zoukankan      html  css  js  c++  java
  • [NOI2018]屠龙勇士(exCRT)

    首先很明显剑的选择是唯一的,直接用multiset即可。

      接下来可以发现每条龙都是一个模线性方程。设攻击第i条龙的剑的攻击力为$s_i$,则$s_ixequiv a_i (mod p_i)$。

      现在需要将方程化成$xequiv c_i (mod m_i)$的形式,从而使用exCRT解决。

      变式:$s_ix+p_iy=a_i$,先同除以$gcd(s_i,p_i)$,再使用exgcd解不定方程,求x的最小正整数解。

      注意判无解,exCRT结束之后注意要使$xgeqslant max(frac{a_i}{s_i})$

     1 #include<set>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=100010;
     9 multiset<ll>S;
    10 bool mark;
    11 int n,k,T;
    12 ll mx,a[N],p[N],more[N],s[N],c[N],m[N];
    13 
    14 ll gcd(ll a,ll b){ return b ? gcd(b,a%b) : a; }
    15 
    16 ll mul(ll a,ll b,ll mod){
    17     ll res=0; a%=mod; b%=mod;
    18     for (; b; a=(a<<1)%mod,b>>=1)
    19         if (b & 1) res=(res+a)%mod;
    20     return res;
    21 }
    22 
    23 void exgcd(ll a,ll b,ll &x,ll &y){
    24     if (!b){ x=1; y=0; return; }
    25     exgcd(b,a%b,y,x); y-=(a/b)*x;
    26 }
    27 
    28 ll inv(ll a,ll b){ ll x,y; exgcd(a,b,x,y); x=(x%b+b)%b; return x; }
    29 
    30 bool merge(ll c1,ll c2,ll m1,ll m2,ll &c3,ll &m3){
    31     ll d=gcd(m1,m2); m3=m1/d*m2;
    32     if (c2<c1) swap(c1,c2),swap(m1,m2);
    33     if ((c2-c1)%d) return 0;
    34     c3=(mul(mul(inv(m1/d,m2/d),(c2-c1)/d,m2/d),m1,m3)+c1)%m3;
    35     return 1;
    36 }
    37 
    38 void work(){
    39     scanf("%d%d",&n,&k); mark=1; mx=0; S.clear();
    40     rep(i,1,n) scanf("%lld",&a[i]);
    41     rep(i,1,n) scanf("%lld",&p[i]);
    42     rep(i,1,n) scanf("%lld",&more[i]);
    43     rep(i,1,k) scanf("%lld",&s[i]),S.insert(s[i]);
    44     rep(i,1,n){
    45         multiset<ll>::iterator it=S.upper_bound(a[i]);
    46         if (it!=S.begin()) it--;
    47         ll s=*it; S.erase(it); S.insert(more[i]);
    48         mx=max(mx,(a[i]-1)/s+1);
    49         ll d=gcd(s,p[i]);
    50         if (a[i]%d) { mark=0; break; }
    51         m[i]=p[i]/d; c[i]=mul(inv(s/d,m[i]),a[i]/d,m[i]);
    52     }
    53     if (!mark) { puts("-1"); return; }
    54     rep(i,2,n) if (!merge(c[i-1],c[i],m[i-1],m[i],c[i],m[i])) { mark=0; break; }
    55     if (!mark) { puts("-1"); return; }
    56     if (c[n]<mx) c[n]+=((mx-c[n]-1)/m[n]+1)*m[n];
    57     printf("%lld
    ",c[n]);
    58 }
    59 
    60 int main(){
    61     freopen("dragon.in","r",stdin);
    62     freopen("dragon.out","w",stdout);
    63     for (scanf("%d",&T); T--; ) work();
    64     return 0;
    65 }
  • 相关阅读:
    重构后的ConditionHelper
    重构ConditionHelper
    用shell求两个文件的差集
    文件落盘的逻辑
    [转]undefined reference问题总结
    动态生成xml文件
    32位,64位的一些问题
    树数据结构的实际应用
    线程池中的栅栏
    关于线程池的理解
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9368077.html
Copyright © 2011-2022 走看看