zoukankan      html  css  js  c++  java
  • NOI2018 屠龙勇士

    一道简单的(EXCRT)
    题目链接


    解析

    我们愉快地发现,攻击每条龙的剑的攻击力是确定的.
    只用一个(Multiset)来维护攻击力即可.
    然后,我们可以把这个题目转化一下.
    假设打第(i)条龙时攻击力是(t_i)
    (t_ixequiv a_i(mod p_i))
    所以只要求解这个方程组即可.


    等等!
    这只能在(a_i<p_i)的情况下成立.
    假设(a_i>p_i),那么可能还没把龙的血量打到(0)就已经是(p)的倍数了.
    怎么办?
    情况变得复杂起来了

    然而,我们仔细地看一看表格
    发现当(a_i>p_i)时,所有的(p_i)都为(1)
    那么只要特判一下就好了.


    那么我们只要求解(t_ixequiv a_i(mod p_i))这个方程组.
    我们普通的(EXCRT)只能求解(t_i=1)的情况,那么这个该如何处理呢?
    很简单,我们列出不定方程(tx+py=a)(为了方便,以后所有的(t_i)等等省略(i))求出(g=gcd(t,p))
    然后用(exgcd)求解这个不定方程.当然啦,如果(a otequiv0(mod g)),那么就输出(-1).
    假设这个方程有解,我们求出了一组解(tx,ty)
    用一个据说是叫做裴蜀定理的东西求出方程通解(x=tx+kfrac{p}{g})
    两边对(frac{p}{g})取模后得(xequiv tx(mod frac{p}{g}))
    我们就成功化简了这个式子!
    剩下的事情就很简单了,直接把(excrt)的板子套上去即可.
    (EXCRT)的讲解戳这里
    还有最重要的一点就是——注意龟速乘

    代码如下

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #include<set>
    #define N (100010)
    #define inf (0x7f7f7f7f)
    #define rg register int
    #define Label puts("NAIVE")
    #define GG ({gg=1,print(-1),ent;break;})
    #define spa print(' ')
    #define ent print('
    ')
    #define rand() (((rand())<<(15))^(rand()))
    typedef long double ld;
    typedef long long LL;
    typedef unsigned long long ull;
    using namespace std;
    inline char read(){
    	static const int IN_LEN=1000000;
    	static char buf[IN_LEN],*s,*t;
    	return (s==t?t=(s=buf)+fread(buf,1,IN_LEN,stdin),(s==t?-1:*s++):*s++);
    }
    template<class T>
    inline void read(T &x){
    	static bool iosig;
    	static char c;
    	for(iosig=false,c=read();!isdigit(c);c=read()){
    		if(c=='-')iosig=true;
    		if(c==-1)return;
    	}
    	for(x=0;isdigit(c);c=read())x=((x+(x<<2))<<1)+(c^'0');
    	if(iosig)x=-x;
    }
    inline char readchar(){
    	static char c;
    	for(c=read();!isalpha(c);c=read())
    	if(c==-1)return 0;
    	return c;
    }
    const int OUT_LEN = 10000000;
    char obuf[OUT_LEN],*ooh=obuf;
    inline void print(char c) {
    	if(ooh==obuf+OUT_LEN)fwrite(obuf,1,OUT_LEN,stdout),ooh=obuf;
    	*ooh++=c;
    }
    template<class T>
    inline void print(T x){
    	static int buf[30],cnt;
    	if(x==0)print('0');
    	else{
    		if(x<0)print('-'),x=-x;
    		for(cnt=0;x;x/=10)buf[++cnt]=x%10+48;
    		while(cnt)print((char)buf[cnt--]);
    	}
    }
    inline void flush(){fwrite(obuf,1,ooh-obuf,stdout);}
    multiset<LL>S;
    set<LL>::iterator it;
    int T,n,m;
    LL c[N],a[N],p[N],rew[N];
    LL gcd(LL a,LL b){
    	if(!b)return a;
    	return gcd(b,a%b);
    }
    void exgcd(LL a,LL b,LL &x,LL &y){
    	if(!b){x=1,y=0;return;}
    	exgcd(b,a%b,y,x),y-=(a/b)*x;
    }
    LL mult(LL a,LL b,LL mod){
    	LL res=0,fu=1;
    	if(a<0)fu=-fu,a=-a;
    	if(b<0)fu=-fu,b=-b;
    	while(b){
    		if(b&1)res=(res+a)%mod;
    		a=(a+a)%mod,b>>=1;
    	}
    	res*=fu;
    	if(res<0)(res+=((-res-1)/mod+1)*mod);
    	return res;
    }
    LL inv(LL a,LL b){
    	LL x,y;
    	exgcd(a,b,x,y);
    	return (x<=0)?(x+b):x;
    }
    bool spj(){
    	for(int i=1;i<=n;i++)
    	if(p[i]>1)return 0;
    	LL x=0;
    	for(int i=2;i<=n;i++)
    	x=max(x,(c[i]-1)/a[i]+1);
    	print(x),ent;
    	return 1;
    }
    int main(){
    	read(T);
    	while(T--){
    		bool gg=0;
    		read(n),read(m),S.clear();
    		for(int i=1;i<=n;i++)read(c[i]);
    		for(int i=1;i<=n;i++)read(p[i]);
    		for(int i=1;i<=n;i++)read(rew[i]);
    		for(int i=1;i<=m;i++){
    			LL x;
    			read(x),S.insert(x);
    		}
    		for(int i=1;i<=n;i++){
    			it=S.upper_bound(c[i]);
    			if(it==S.begin())a[i]=*it;
    			else it--,a[i]=*it;
    			S.erase(it),S.insert(rew[i]);
    		}
    		if(spj())continue;
    		for(int i=1;i<=n;i++)a[i]%=p[i];
    		for(int i=1;i<=n;i++)
    		if(a[i]==0){
    			if(p[i]==c[i])
    			a[i]=1,p[i]=1,c[i]=0;
    			else GG;
    		}
    		if(gg)continue;
    		for(int i=1;i<=n;i++){
    			LL A=a[i],C=c[i],P=p[i];
    			LL g=gcd(A,P);if(C%g!=0)GG;
    			LL tx,ty; exgcd(A,P,tx,ty);
    			P/=g,tx=(tx%P+P)%P,C=mult(tx,C/g,P);
    			a[i]=A,c[i]=C,p[i]=P;
    		}
    		if(gg)continue;
    		LL c1=c[1],p1=p[1];
    		for(int i=2;i<=n;i++){
    			LL mo=p[i],c2=c[i];
    			LL t=gcd(p1,mo),s=inv(p1/t,mo/t),tc=c1,tm=p1;
    			if((c2-c1)%t!=0)GG;
    			p1=(mo/t*tm),c1=(tc+mult(tm,mult(s,(c2-c1)/t,(mo/t)),p1))%p1;
    		}
    		if(gg)continue;
    		if(c1<0)c1+=((-c1-1)/p1+1)*p1;
    		print(c1%p1),ent;
    	}
    	return flush(),0;
    }
    
  • 相关阅读:
    朴英敏: 用crash工具分析Linux内核死锁的一次实战【转】
    ext3,ext4,xfs和btrfs文件系统性能对比【转】
    STM32MP157——Remoteproc和RPMsg【转】
    使用edac工具来检测服务器内存故障.【转】
    面试题-python 什么是生成器(generator)?
    面试题-python 什么是迭代器(Iterator)?
    面试题-python 浅拷贝和深拷贝(copy模块)
    selenium+python自动化104-如何获取隐藏元素text文本
    面试题-websocket 接口如何测试?
    jmeter压测学习47-发soap请求测试webservice接口
  • 原文地址:https://www.cnblogs.com/Romeolong/p/10076264.html
Copyright © 2011-2022 走看看