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 中国剩余定理

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

  • 相关阅读:
    HDU 1850 Being a Good Boy in Spring Festival
    UESTC 1080 空心矩阵
    HDU 2491 Priest John's Busiest Day
    UVALive 6181
    ZOJ 2674 Strange Limit
    UVA 12532 Interval Product
    UESTC 1237 质因子分解
    UESTC 1014 Shot
    xe5 android listbox的 TMetropolisUIListBoxItem
    xe5 android tts(Text To Speech)
  • 原文地址:https://www.cnblogs.com/syc233/p/13654606.html
Copyright © 2011-2022 走看看