[BZOJ2742][HEOI2012]Akai的数学作业[推导]

题意

给定各项系数,求一元 (n) 次方程的有理数解。

(nleq 100)

分析

  • 设答案为 (frac{p}{q}) ,那么多项式可以写成 (a_0frac{p}{q}+a_1frac{p^2}{q^2}+cdots a_nfrac{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) 必为 (q) 倍数。

  • 因为最低项可能为 (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
",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
",ans[i].fz,ans[i].fm);
		else printf("%d
",ans[i].fz);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/yqgAKIOI/p/9814710.html