zoukankan      html  css  js  c++  java
  • [TJOI2009]猜数字

    [TJOI2009]猜数字

    中国剩余定理+龟速乘

    这个大概就是中国剩余定理的板子题了啊。。。

    中国剩余定理:

    问题:

    (m_1,m_2...m_n,)是两两互质的正整数,

    求解线性同余方程组:

    [f(n)=egin{cases} xequiv a_1pmod {m_1}\ xequiv a_2pmod {m_2}\ ... ...\ xequiv a_npmod {m_n}\ end{cases}]

    的解(x)

    解法:

    (M=prod_{i=1}^n,M_i=M/m_i)

    (t)是同余方程(M_it_iequiv 1pmod {m_i})的一个解

    关于怎么解同余方程

    然后答案就是

    [x=sum_{i=1}^n a_im_it_i ]

    证明:

    因为(M_i)是处(m_i)外所有数的倍数,所以

    [forall k ot=i,a_iM_it_iequiv 0pmod {m_k} ]

    而且

    [a_iM_it_iequiv a_ipmod {m_i} ]

    [x=sum_{i=1}^na_iM_it_i ]

    原方程成立。

    通解:

    [x=sum_{i=1}^n a_im_it_i ]

    是问题的一个特殊解,通解为

    [x+kM(kin Z) ]

    证明:

    显然(大雾)

    龟速乘:

    (O(logn))的其他题解里都有,很好理解,就不说了。

    (O(1))的龟速乘:

    当两个数乘起来爆 long long 的时候,需要用快速乘,虽然O(1)的比O(logn)的快了许多,但是他还是没有普通乘快,所以我叫他龟速乘qwq

    Code

    
    inline ll qmul(ll x,ll y,ll mod)
    {
        x%=mod;y%=mod;
        return ((x*y-(ll)(((long double)x*y+0.5)/mod)*mod)%mod+mod)%mod;
    }
    
    

    这个。。。也挺好理解啊,而且也没法解释啊qwq可意会不可言传

    然后就是打板子了emmmm

    Code

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    
    const int N = 1e5+1;
    ll n,ans;
    ll M=1,Mi,a[N],m[N];
    
    inline void file()
    {freopen("text.in","r",stdin);freopen("text.out","w",stdout);}
    inline void closefile()
    {fclose(stdin);fclose(stdout);}
    
    inline void readx(ll &x)
    {
    	x=0;int s=1;char ch=getchar();
    	while(ch<'0'||ch>'9')
    	{if(ch=='-') s=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')
    	{x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	x*=s;
    }
    
    inline ll qmul(ll x,ll y,ll mod)
    {
        x%=mod;y%=mod;
        return ((x*y-(ll)(((long double)x*y+0.5)/mod)*mod)%mod+mod)%mod;
    }
    
    inline void exgcd(ll a,ll b,ll &x,ll &y)
    {
    	if(b==0) {x=1;y=0;return;}
    	exgcd(b,a%b,y,x);
    	y=y-a/b*x;
    }
    
    inline void china()
    {
    	for(ll i=1;i<=n;++i) readx(a[i]);
    	for(ll i=1;i<=n;++i)
    	{
    		readx(m[i]);
    		a[i]=(a[i]%m[i]+m[i])%m[i];
    		M*=m[i];
    	}
    	for(ll i=1;i<=n;++i)
    	{
    		Mi=M/m[i];
    		ll x,y;
    		exgcd(Mi,m[i],x,y);
    		x=(x%m[i]+m[i])%m[i];
    		ans=((ans+qmul(qmul(a[i],x,M),Mi,M)%M)+M)%M;
    	}
    	ans=(ans+M)%M;
    	printf("%lld
    ",ans);
    }
    
    int main()
    {
    //	file();
    
    	readx(n);
    	china();
    
    //	closefile();
    	return 0;
    }
    
    
  • 相关阅读:
    Shell脚本最佳实践
    tmux会话断电保存自动恢复
    [JD15] 括号匹配方案
    [LeetCode 187.] 重复的DNA序列
    [LeetCode 162.] 寻找峰值
    基于 Chocolatey 打造 Windows 开发环境
    [LeetCode 71.] 简化路径 【IO】
    【栈】栈排序
    [LeetCode 829.] 连续整数求和
    [LeetCode 29.] 两数相除
  • 原文地址:https://www.cnblogs.com/oierwyh/p/11376341.html
Copyright © 2011-2022 走看看