2742: [HEOI2012]Akai的数学作业

2742: [HEOI2012]Akai的数学作业

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 510   Solved: 213
[ Submit][ Status][ Discuss]

Description

这里是广袤无垠的宇宙这里是一泻千里的银河
这里是独一无二的太阳系
这里是蔚蓝色的地球
这里,就是这里,是富饶的中国大陆!
这里是神奇的河北大地
这里是美丽的唐山
这里是神话般的唐山一中
这里是Akai曾经的教室
黑板上还留有当年Akai做过的数学作业,其实也并不是什么很困难的题目:
给出一个一元n次方程:
a0 + a1x + a    2   x2 +…+ anxn= 0
求此方程的所有有理数解。


 ” Akai至今还深刻记得当年熬夜奋战求解的时光
他甚至还能记得浪费了多少草稿纸
但是却怎么也想不起来最后的答案是多少了
你能帮助他么?

Input

第一行一个整数n。第二行n+1个整数,分别代表a    0 a n

Output

第一行输出一个整数t,表示有理数解的个数
接下来t行,每行表示一个解
解以分数的形式输出,要求分子和分母互质,且分母必须是正整数特殊的,如果这个解是一个整数,那么直接把这个数输出
等价的解只需要输出一次
所有解按照从小到大的顺序输出

Sample Input

3
-24 14 29 6

Sample Output

3
-4
-3/2
2/3

HINT

【数据范围】

对于30%的数据,n<=10 

对于100%的数据,n <= 100,|a i| <= 2*10^7,an≠ 0

Source

[ Submit][ Status][ Discuss]




数学功底太差啦。。不会做= =

最后,暴力分解an,a0的质因子,枚举判断就行了。数值太大就取模。。

如果a0 == 0?两边同时除以x^k,让最小的ai != 0变成a0就行了,特判此时有一根0

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std;

typedef long long LL;
const int maxn = 5050;
const int N = 111;
const int T = 5;
const LL mo[5] = {299979457,299960249,299941561,299922113,299902541};

struct data{
	int A,B,typ; data(){}
	data(int A,int B,int typ):
		A(A),B(B),typ(typ){}
	bool operator != (const data &b) const
	{
		return A != b.A || B != b.B || typ != b.typ;
	}
	bool operator < (const data &b) const
	{
		if (typ < b.typ) return 1;
		if (typ > b.typ) return 0;
		if (typ > 0) return 1LL*A*b.B < 1LL*B*b.A;
		else return 1LL*A*b.B > 1LL*B*b.A;
	}
}Ans[10000000];

int n,ta,tb,tot,cur = 1,a[N],A[maxn],B[maxn];
LL mq[N][5],mp[N][5];

int gcd(const int &x,const int &y) {return !y?x:gcd(y,x%y);}

void Mul(LL *C,LL *D,LL k)
{
	for (int i = 0; i < T; i++)
		D[i] = C[i]*k%mo[i];
}

void Add(int *C,LL *x,LL *y,LL k)
{
	for (int i = 0; i < T; i++)
		C[i] += x[i]*y[i]%mo[i]*k%mo[i],C[i] = (C[i] + mo[i]) % mo[i];
}

void Dec(int *C,LL *x,LL *y,LL k)
{
	for (int i = 0; i < T; i++)
		C[i] -= x[i]*y[i]%mo[i]*k%mo[i],C[i] = (C[i] + mo[i]) % mo[i];
}

void Work(int Num,int &tt,int *C)
{
	int sqr = sqrt(Num);
	for (int i = 1; i <= sqr; i++)
		if (Num % i == 0)
		{
			C[++tt] = i;
			C[++tt] = Num / i;
		}
	if (sqr*sqr == Num) C[tt--] = 0;
}

void Judge(int q,int p)
{
	int g = gcd(q,p); q /= g; p /= g;
	int G[2][T]; memset(G,0,sizeof(G));
	for (int i = 1; i <= n; i++)
	{
		Mul(mq[i-1],mq[i],q),Mul(mp[i-1],mp[i],p);
		//for (int j = 0; j < T; j++) printf("%d ",mq[i][j]); cout << endl;
		//for (int j = 0; j < T; j++) printf("%d ",mp[i][j]); cout << endl;
	}
	for (int i = 0; i <= n; i++)
	{
		Add(G[0],mp[n-i],mq[i],a[i]);
		if (i&1) Dec(G[1],mp[n-i],mq[i],a[i]);
		else Add(G[1],mp[n-i],mq[i],a[i]);
		//for (int j = 0; j < T; j++) printf("%d ",G[0][j]); cout << endl;
		//for (int j = 0; j < T; j++) printf("%d ",G[1][j]); cout << endl;
	}
	bool flag0,flag1; flag0 = flag1 = 1;
	for (int i = 0; i < T; i++)
	{
		if (G[0][i] != 0) flag0 = 0;
		if (G[1][i] != 0) flag1 = 0;
	}
	if (flag0) Ans[++tot] = data(q,p,1);
	if (flag1) Ans[++tot] = data(q,p,-1);
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> n; int pos = 0;
	for (int i = 0; i <= n; i++) scanf("%d",&a[i]);
	while (!a[pos]) ++pos;
	if (pos)
	{
		Ans[++tot] = data(0,1,1); n -= pos;
		for (int i = 0; i <= n; i++) a[i] = a[i+pos];
	}
	Work(abs(a[0]),ta,A); Work(abs(a[n]),tb,B);
	//cout << ta << endl; for (int i = 1; i <= ta; i++) printf("%d ",A[i]); cout << endl;
	//cout << tb << endl; for (int i = 1; i <= tb; i++) printf("%d ",B[i]); cout << endl;
	for (int i = 0; i < T; i++) mq[0][i] = mp[0][i] = 1;
	for (int i = 1; i <= ta; i++)
		for (int j = 1; j <= tb; j++)
			Judge(A[i],B[j]);
	sort(Ans + 1,Ans + tot + 1);
	for (int i = 2; i <= tot; i++)
		if (Ans[i] != Ans[i-1]) Ans[++cur] = Ans[i];
	cout << cur << endl;
	for (int i = 1; i <= cur; i++)
	{
		if (Ans[i].typ == -1) putchar('-');
		if (Ans[i].B == 1) printf("%d\n",Ans[i].A);
		else printf("%d/%d\n",Ans[i].A,Ans[i].B);
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值