zoukankan      html  css  js  c++  java
  • 题解「Luogu4774 [NOI2018]屠龙勇士」

    转载注明来源:https://www.cnblogs.com/syc233/p/13654606.html


    首先发现对每条龙使用的剑是固定的,于是可以用multiset预处理出对每条龙使用的剑 (b_i)

    然后发现题其实是要求一堆形如这个的式子:

    [a_i-x cdot b_i+y cdot p_i=0 (x,y in ) ]

    明显这是一个二元一次不定方程,把它化成标准形式:

    [x cdot b_i+y cdot p_i=a_i (x,y in ) ]

    用exgcd求出这个方程的一组通解 (x_0,y_0) 。若无解,则直接输出 (-1) ,否则有(为了方便,以下均使用 ((i,j)) 表示 ({ m{gcd}}(i,j)) ):

    [x=frac{a_i}{(b_i,p_i)}x_0+k cdot frac{p_i}{(b_i,p_i)} iff x equiv x_0 ({ m{mod}} frac{p_i}{(b_i,p_i)}) ]

    对每一个二元一次不定方程进行上述操作,令 (A_i=x_0,B_i=frac{p_i}{(b_i,p_i)}) ,则需要求解如下同余方程组:

    [egin{cases} x equiv A_1 ({ m{mod}} B_1)\ x equiv A_2 ({ m{mod}} B_2)\ cdots \ x equiv A_n ({ m{mod}} B_n)\ end{cases} ]

    用exCRT合并即可。

    特判 (p_i=1) ,让所有龙的血量非正即可。


    ( ext{Code}:)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <set>
    #define maxn 100005
    #define Rint register int
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long lxl;
    
    template <typename T>
    inline void read(T &x)
    {
    	x=0;T f=1;char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	x*=f;
    }
    
    inline lxl fti(lxl a,lxl b,lxl mod)
    {
    	lxl res=0;
    	while(b>0)
    	{
    		if(b&1) (res+=a)%=mod;
    		(a+=a)%=mod;
    		b>>=1;
    	}
    	return res;
    }
    
    inline lxl exgcd(lxl a,lxl b,lxl &x,lxl &y)
    {
    	if(!b) {x=1,y=0;return a;}
    	lxl res=exgcd(b,a%b,x,y);
    	lxl z=x;x=y;y=z-(a/b)*y;
    	return res;
    }
    
    int n,m;
    lxl a[maxn],p[maxn],b[maxn],aw[maxn];
    multiset<lxl> s;
    #define IT multiset<lxl>::iterator
    
    lxl A[maxn],B[maxn];
    
    int main()
    {
    	// freopen("P4774.in","r",stdin);
    	int T;read(T);
    	while(T--)
    	{
    		read(n),read(m);
    		s.clear();
    		lxl mx=0;
    		for(int i=1;i<=n;++i) read(a[i]);
    		for(int i=1;i<=n;++i) read(p[i]),mx=max(mx,p[i]);
    		for(int i=1;i<=n;++i) read(aw[i]);
    		for(int i=1;i<=m;++i)
    		{
    			lxl w;read(w);
    			s.insert(w);
    		}
    		bool flag=true;
    		for(int i=1;i<=n;++i)
    		{
    			IT it=s.upper_bound(a[i]);
    			if(it!=s.begin()) --it;
    			b[i]=*it;
    			s.erase(it);
    			s.insert(aw[i]);
    			lxl x,y,d=exgcd(b[i],p[i],x,y);
    			if(a[i]%d) {flag=false;break;}
    			a[i]/=d,p[i]/=d;
    			x=fti(x,a[i],p[i]);
    			B[i]=p[i];
    			A[i]=(x%B[i]+B[i])%B[i]; 
    		}
    		if(!flag) {puts("-1");continue;}
    		if(mx==1)
    		{
    			lxl ans=0;
    			for(int i=1;i<=n;++i)
    				ans=max(ans,(a[i]+b[i]-1)/b[i]);
    			printf("%lld
    ", ans);
    			continue;
    		}
    		lxl M=B[1],ans=A[1];
    		for(int i=2;i<=n;++i)
    		{
    			lxl b1=M,b2=B[i],c=(A[i]-ans%b2+b2)%b2,x,y;
    			lxl d=exgcd(b1,b2,x,y);
    			if(c%d) {flag=false;break;}
    			b2/=d,c/=d;
    			x=fti(x,c,b2);
    			ans+=M*x;
    			M*=B[i]/d;
    			(ans+=M)%=M;
    		}
    		if(!flag) {puts("-1");continue;}
    		printf("%lld
    ",(ans+M)%M);
    	}
    	return 0;
    }
    

    参考资料:

    扩展欧几里得定理

    CRT 中国剩余定理

    其实是忘完了去复习了一下

  • 相关阅读:
    bzoj 1017 魔兽地图DotR
    poj 1322 chocolate
    bzoj 1045 糖果传递
    poj 3067 japan
    timus 1109 Conference(二分图匹配)
    URAL 1205 By the Underground or by Foot?(SPFA)
    URAL 1242 Werewolf(DFS)
    timus 1033 Labyrinth(BFS)
    URAL 1208 Legendary Teams Contest(DFS)
    URAL 1930 Ivan's Car(BFS)
  • 原文地址:https://www.cnblogs.com/syc233/p/13654606.html
Copyright © 2011-2022 走看看