[BZOJ2742][HEOI2012]Akai的數學作業[推導]
阿新 • • 發佈:2018-11-10
題意
給定各項係數,求一元 \(n\) 次方程的有理數解。
\(n\leq 100\)。
分析
設答案為 \(\frac{p}{q}\) ,那麼多項式可以寫成 \(a_0\frac{p}{q}+a_1\frac{p^2}{q^2}+\cdots a_n\frac{p^n}{q^n}\) 的形式。
左右乘以 \(q^n\) :得到:\(\sum_{i=0}^n {a_ip^iq^{n-i}}=0\) 。
- 可以推出
- \(a_0q^n=p*A\) ;
- \(a_np^n=q*B\) ;
因為 \(p,q\) 互質,所以得到 \(a_0\) 必為 \(p\) 倍數, \(a_n\)
因為最低項可能為 \(0\),所以以第一個不為 \(0\) 的項作為基準,結論是一致的。
可以通過對幾個大質數取模的方式判斷是否為 \(0\)。
程式碼
#include<bits/stdc++.h> using namespace std; #define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].last,v=e[i].to) #define rep(i,a,b) for(int i=a;i<=b;++i) #define pb push_back typedef long long LL; inline int gi(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();} return x*f; } template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;} template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;} const int N=107; int n,mod,cnt; int a[N],bp[N],bq[N]; int M[]={19260817,998244353,1000000007,19491001,48271}; vector<int>v0,vn; void add(int &a,int b){a+=b;if(a>=mod) a-=mod;} bool check(int p,int q){ for(int j=0;j<5;++j){ mod=M[j];int tmp=0; bp[0]=bq[0]=1; for(int i=1;i<=n;++i) bp[i]=1ll*bp[i-1]*p%mod,bq[i]=1ll*bq[i-1]*q%mod; rep(i,0,n) add(tmp,(1ll*a[i]*bp[i]%mod*bq[n-i]%mod+mod)%mod); if(tmp) return 0; } return 1; } int gcd(int a,int b){ return !b?a:gcd(b,a%b); } struct fs{ int fz,fm; bool operator <(const fs &b)const{ return 1ll*fz*b.fm<1ll*b.fz*fm; } bool operator !=(const fs &b)const{ return fz!=b.fz||fm!=b.fm; } }; vector<fs>ans; int main(){ n=gi(); rep(i,0,n) a[i]=gi(); int x=0; while(!a[x]) ++x; if(x) v0.pb(0); x=abs(a[x]); for(int i=1,l=(int)sqrt(x);i<=l;++i)if(x%i==0){ v0.pb(i),v0.pb(-i); if(i*i!=x) v0.pb(x/i),v0.pb(-x/i); } x=abs(a[n]); for(int i=1,l=(int)sqrt(x);i<=l;++i)if(x%i==0){ vn.pb(i); if(i*i!=x) vn.pb(x/i); } for(auto p:v0) for(auto q:vn){ int x=p,y=q; if(check(x,y)){ int g=gcd(x,y); x/=g,y/=g; ans.pb((fs){x,y}); } } sort(ans.begin(),ans.end()); for(int i=0;i<ans.size();++i) if(i==0||ans[i]!=ans[i-1]) ++cnt; printf("%d\n",cnt); for(int i=0;i<ans.size();++i) if(i==0||ans[i]!=ans[i-1]){ if(ans[i].fm!=1) printf("%d/%d\n",ans[i].fz,ans[i].fm); else printf("%d\n",ans[i].fz); } return 0; }