[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;
}