[TJOI2009]猜数字
中国剩余定理+龟速乘
这个大概就是中国剩余定理的板子题了啊。。。
中国剩余定理:
问题:
若\(m_1,m_2...m_n,\)是两两互质的正整数,
求解线性同余方程组:
\[f(n)=\begin{cases} x\equiv a_1\pmod {m_1}\\ x\equiv a_2\pmod {m_2}\\ ... ...\\ x\equiv a_n\pmod {m_n}\\ \end{cases}\]
的解\(x\)。
解法:
设\(M=\prod_{i=1}^n,M_i=M/m_i\)
\(t\)是同余方程\(M_it_i\equiv 1\pmod {m_i}\)的一个解
然后答案就是
\[x=\sum_{i=1}^n a_im_it_i\]
证明:
因为\(M_i\)是处\(m_i\)外所有数的倍数,所以
\[\forall k\not=i,a_iM_it_i\equiv 0\pmod {m_k}\]
而且
\[a_iM_it_i\equiv a_i\pmod {m_i}\]
\[x=\sum_{i=1}^na_iM_it_i\]
原方程成立。
通解:
\[x=\sum_{i=1}^n a_im_it_i\]
是问题的一个特殊解,通解为
\[x+kM(k\in 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\n",ans); } int main() { // file(); readx(n); china(); // closefile(); return 0; }