• 【[NOI2018]屠龙勇士】


    发现好像都是化掉系数之后套上(ExCrt)的板子

    这好像是一个真正的扩展扩展中国剩余定理

    我们要处理的方程是这样的形式

    [c_ixequiv b_i(mod a_i) ]

    其中(c)用一个(std::multiset)处理就好了

    好像不是普通(excrt)可以处理的形式啊

    思考一下这个方程的本质是什么,(c_ix=k_ia_i+b_i)

    所以如果我们有两个方程

    [c_1xequiv b_1(mod a_1) ]

    [c_2xequiv b_2(mod a_2) ]

    我们需要像(crt)那样合并起来

    我们开始化柿子了

    [x=frac{k_1a_1+b_1}{c_1}=frac{k_2a_2+b_2}{c_2} ]

    所以就有

    [a_2c_1k_2+b_2c_1=a_1c_2k_1+b_1c_2 ]

    [a_2c_1k_2=a_1c_2k_1+b_1c_2-b_2c_1 ]

    根据贝祖定理,这个方程有解条件是(gcd(a_2c_1,a_1c_2)|(b_1c_2-b_2c_1))

    如果有解的话,我们设(t=gcd(a_2c_1,a_1c_2)),两边除以(t)

    [frac{a_2c_1k_2}{t}=frac{a_1c_2k_1}{t}+frac{b_1c_2-b_2c_1}{t} ]

    显然我们可以写成一个同余式

    [frac{a_2c_1k_2}{t}equiv frac{b_1c_2-b_2c_1}{t} (mod frac{a_1c_2}{t}) ]

    之后设(inv=(frac{a_2c_1}{t},frac{a_1c_2}{t})),即(frac{a_2c_1}{t})(mod) (frac{a_1c_2}{t})意义下的乘法逆元

    两边乘以(inv)

    [k_2equiv inv*frac{b_1c_2-b_2c_1}{t} (mod frac{a_1c_2}{t}) ]

    改写成等式

    [k_2= inv*frac{b_1c_2-b_2c_1}{t}+y imesfrac{a_1c_2}{t} ]

    我们把(k_2)回带到(c_2x=k_2a_2+b_2)

    [c_2x=inv*frac{b_1c_2-b_2c_1}{t}*a_2+y imesfrac{a_1c_2a_2}{t}+b_2 ]

    再改写成同余式

    [c_2xequiv inv*frac{b_1c_2-b_2c_1}{t}\%(frac{a_1c_2}{t})*a_2+b_2(mod frac{a_1c_2a_2}{t}) ]

    我们只需要顺次合并这些方程就好了,一旦出现无解就输出(-1)好了

    一个坑点是(a=1)时解出来会是(0),好像和实际要求不太一样,所以对于这样情况直接模拟特判就好了

    之后因为非常的懒没用快速乘,用了__int128

    代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<set>
    #define re register
    #define maxn 100005
    #define LL __int128
    #define min(a,b) ((a)<(b)?(a):(b))
    #define INF 9999999999999
    #define max(a,b) ((a)>(b)?(a):(b))
    #define set_it std::multiset<LL>::iterator
    std::multiset<LL> s;
    int n,m;
    LL a[maxn],b[maxn],c[maxn],res[maxn];
    LL gcd(LL a,LL b){ return !b?a:gcd(b,a%b);}
    LL exgcd(LL a,LL b,LL &x,LL &y)
    {
    	if(!b) return x=1,y=0,a;
    	LL r=exgcd(b,a%b,y,x);
    	y-=a/b*x;
    	return r;
    }
    inline LL pre(LL x)
    {
    	s.insert(x);
    	set_it i=s.find(x);
    	if(i==s.begin()) return -INF;
    	--i;return *i;
    }
    inline void del(LL x)
    {
    	set_it i=s.find(x);
    	s.erase(i);
    }
    inline int check(LL x)
    {
    	if(s.find(x)!=s.end()) return 1;
    	return 0;
    }
    inline LL read()
    {
    	char c=getchar();
    	LL x=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9')
    		x=(x<<3)+(x<<1)+c-48,c=getchar();
    	return x;
    }
    inline LL inv(LL a,LL b)
    {
    	LL x,y;
    	LL r=exgcd(a,b,x,y);
    	return (x%b+b)%b;
    }
    void write(LL x)
    {
        if(x>9) write(x/10);
        putchar(x%10+48);
    }
    inline LL did(LL a,LL b)
    {
    	if(a%b==0) return a/b;
    	return a/b+1;
    }
    inline void tepan()
    {
    	LL ans=0;
    	for(re int i=1;i<=n;i++)
    		ans=max(ans,did(b[i],c[i]));
    	write(ans),puts("");
    }
    inline void solve()
    {
    	s.clear();
    	LL x;
    	int flag=0;
    	n=read(),m=read();
    	for(re int i=1;i<=n;i++) b[i]=read();
    	for(re int i=1;i<=n;i++) a[i]=read(),flag|=(a[i]!=1);
    	for(re int i=1;i<=n;i++) res[i]=read();
    	for(re int i=1;i<=m;i++) x=read(),s.insert(x);
    	for(re int i=1;i<=n;i++)
    	{
    		if(check(b[i])) c[i]=b[i],del(b[i]);
    		else
    		{
    			LL now=pre(b[i]);
    			del(b[i]);
    			if(now==-INF)
    			{
    				set_it it=s.begin();
    				c[i]=*it;
    				s.erase(it);
    			}
    			else c[i]=now,del(now);
    		}
    		s.insert(res[i]);
    	}
    	if(!flag)
    	{
    		tepan();
    		return;
    	}
    	LL a1=a[1],b1=b[1],c1=c[1];
    	for(re int i=2;i<=n;i++)
    	{
    		LL a2=a[i],b2=b[i],c2=c[i];
    		LL r=gcd(c2*a1,c1*a2);
    		if((b1*c2-b2*c1)%r) 
    		{
    			puts("-1");
    			return;
    		}
    		if((c2*a1/r)<(c1*a2/r)) std::swap(a1,a2),std::swap(b1,b2),std::swap(c1,c2);
    		LL P=a1*c2/r,Inv=inv(c1*a2/r,a1*c2/r);
    		b1=((Inv*(((b1*c2-b2*c1)/r)%P+P)%P*a2))+b2;
    		a1=a1*a2*c2/r;
    		c1=c2;
    	}
    	LL y;
    	if(b1%gcd(a1,c1))
    	{
    		puts("-1");
    		return;
    	}
    	LL r=exgcd(c1,a1,x,y);
    	LL t=a1/r;
    	x=(x*(b1/r)%t+t)%t;
    	write(x);
    	puts("");
    }
    int main()
    {
    	int T;
    	T=read();
    	while(T--) solve();
    	return 0;
    }
    
  • 相关阅读:
    mariadb
    Linux下安装配置virtualenv与virtualenvwrapper
    配置安装源
    Redis哨兵
    Android 常用工具类之DeviceInfoUtil
    Android 常用工具类之RuntimeUtil
    android 中的几种目录
    listview 滑动以后设置最上面一行为整行展示
    Android 常用工具类之SPUtil,可以修改默认sp文件的路径
    android 在应用中切换语言
  • 原文地址:https://www.cnblogs.com/asuldb/p/10205688.html
Copyright © 2020-2023  润新知