Akai的数学作业

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

Description

  这里是广袤无垠的宇宙这里是一泻千里的银河,这里是独一无二的太阳系,这里是蔚蓝色的地球
  这里,就是这里,是富饶的中国大陆!
  这里是神奇的河北大地,这里是美丽的唐山,这里是神话般的唐山一中,这里是Akai曾经的教室
  黑板上还留有当年Akai做过的数学作业,其实也并不是什么很困难的题目:
  “
    给出一个一元n次方程:
    a0 + a1x + a 2 x2 +…+ anxn= 0
    求此方程的所有有理数解。
  ”
  Akai至今还深刻记得当年熬夜奋战求解的时光,他甚至还能记得浪费了多少草稿纸。
  但是却怎么也想不起来最后的答案是多少了,你能帮助他么?

Input

  第一行一个整数n。第二行n+1个整数,分别代表a0 到 an

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

Main idea

  给出一个一元n次方程:A0+A1*x+A2*x^2+…+An*x^n,求出这个方程的所有有理数解。

Solution

  这必然是一道数论题。首先我们发现了题目的一个非常重要的特征:求的是有理数解
  立马想到了分解因式,因为要的是有理数解,所以原方程肯定可以表示成:

  x就是q/p。

  然后再来思考一下。我们先从最简单的情况开始处理,也就是A0≠0,An≠0的情况。
  显然可以知道p一定是An分出来的,q一定是A0分出来的,那么一定有p是An的约数,q是A0的约数,那么这时候所有的情况就应该是

  仔细推一下式子,发现了一个规律:几个约数相乘的情况所表达出的集合和不考虑相乘情况的集合是一样的!那么处理就简单了很多。

  由于可能有前几项系数=0的情况,所以我们从A0的想法出发,找到第一个系数非0的项将这一项的约数存下来(如果不是A0的话则在答案中加一个0),然后从后往前找找到第一个非0的存下它的约数。然后O(约数个数)^2枚举任意两种情况的q/p放到原式里面判断(答案有可能是负数所以还要检查一下-q/p可不可行)然后在检查的时候发现了一个问题,数字要么精度误差过大要么就是爆出int范围了,我们想到了通分,分子分母同乘上p^n,避免了精度问题。

  以n=3的举个例子:将原式

  

  转化为

  然后我们就可以不管分母了,用这样的方法解决了精度问题。那么怎么解决爆int范围的问题呢?我们发现,在每次操作的时候都对一个质数取模的话错解的几率不是非常大,那么我们就可以大胆地取模几个质数来判断,如果不放心可以多取模几个。

  BearChild发现了一个神奇的质数:50033(如果使用这个质数的话是不需要用其余几个质数判断的)。

  这样进行累加和是否为0的判断,可行的话将每个答案存下来,然后sort一遍输出即可。

Code

 #include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std; const int ONE=;
const int MOD=; int n;
int A[ONE];
int divisor[ONE][],num[];
int p[ONE];
int q[ONE];
int Repeat[ONE];
int cnt; struct power
{
int l,r;
int value;
}a[ONE]; int cmp(const power &a,const power &b)
{
return (double)a.l/a.r < (double)b.l/b.r;
} int get()
{
int res,Q=; char c;
while( (c=getchar())< || c>)
if(c=='-')Q=-;
if(Q) res=c-;
while((c=getchar())>= && c<=)
res=res*+c-;
return res*Q;
} int gcd(int a,int b)
{
int r=a%b;
while(r)
{
a=b;
b=r;
r=a%b;
}
return b;
} void Deal(int x,int PD)
{
for(int i=;i<=x;i++)
{
if(!(x%i)) divisor[++num[PD]][PD]=i;
}
} int Check(int x,int y)
{
p[]=q[]=;
for(int i=;i<=n;i++)
{
p[i]=(long long)p[i-]*y % MOD; q[i]=(long long)q[i-]*x % MOD;
} long long res=;
for(int i=;i<=n;i++)
{
res=(res+(long long)p[n-i]*q[i]*A[i]) % MOD;
} if(!res) return ;
return ;
} int main()
{
n=get();
for(int i=;i<=n;i++) A[i]=get();
if(A[]==)
{
a[++cnt].l=; a[cnt].r=;
}
for(int i=;i<=n;i++)
{
if(A[i])
{
Deal(abs(A[i]),);
break;
}
} for(int i=n;i>=;i--)
{
if(A[i])
{
Deal(abs(A[i]),);
break;
}
} for(int i=;i<=num[];i++)
for(int j=;j<=num[];j++)
{
int x=divisor[i][];
int y=divisor[j][];
if(gcd(x,y)!=) continue;
if(Check(x,y))
{
a[++cnt].l=x;
a[cnt].r=y;
}
if(Check(-x,y))
{
a[++cnt].l=-x;
a[cnt].r=y;
}
} sort(a+,a+cnt+,cmp);
printf("%d\n",cnt);
for(int i=;i<=cnt;i++)
{
if(a[i].r==) printf("%d\n",a[i].l);
else printf("%d/%d\n",a[i].l,a[i].r);
} }

【BZOJ2742】【HEOI2012】Akai的数学作业 [数论]的更多相关文章

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

    题意 给定各项系数,求一元 \(n\) 次方程的有理数解. \(n\leq 100\). 分析 设答案为 \(\frac{p}{q}\) ,那么多项式可以写成 \(a_0\frac{p}{q}+a_1 ...

  2. BZOJ 2742: [HEOI2012]Akai的数学作业

    2742: [HEOI2012]Akai的数学作业 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 535  Solved: 226[Submit][S ...

  3. LuoguP5390 [Cnoi2019]数学作业(数论)

    转进制,然后发现贡献只有\(1_{(2)}\),取奇数个的子集方案是\(2^{n-1}\) #include <iostream> #include <cstdio> #inc ...

  4. 洛谷P3216 [HNOI2011] 数学作业 [矩阵加速,数论]

    题目传送门 数学作业 题目描述 小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题: 给定正整数 N和 M,要求计算 Concatenate (1 .. N)Mod M 的值,其中 C ...

  5. BZOJ-2326 数学作业 矩阵乘法快速幂+快速乘

    2326: [HNOI2011]数学作业 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 1564 Solved: 910 [Submit][Statu ...

  6. bzoj2326: [HNOI2011]数学作业

    矩阵快速幂,分1-9,10-99...看黄学长的代码理解...然而他直接把答案保存在最后一行(没有说明...好吧应该是我智障这都不知道... #include<cstdio> #inclu ...

  7. BZOJ 2326: [HNOI2011]数学作业( 矩阵快速幂 )

    BZOJ先剧透了是矩阵乘法...这道题显然可以f(x) = f(x-1)*10t+x ,其中t表示x有多少位. 这个递推式可以变成这样的矩阵...(不会用公式编辑器...), 我们把位数相同的一起处理 ...

  8. CJOJ 1331 【HNOI2011】数学作业 / Luogu 3216 【HNOI2011】数学作业 / HYSBZ 2326 数学作业(递推,矩阵)

    CJOJ 1331 [HNOI2011]数学作业 / Luogu 3216 [HNOI2011]数学作业 / HYSBZ 2326 数学作业(递推,矩阵) Description 小 C 数学成绩优异 ...

  9. [luogu P3216] [HNOI2011]数学作业

    [luogu P3216] [HNOI2011]数学作业 题目描述 小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题: 给定正整数 N 和 M,要求计算 Concatenate (1 ...

随机推荐

  1. 当我们访问不了虚拟机上ip上的web页面,是因为在window上要添加映射

    在主机上添加映射步骤 1.打开C盘 注意:用nopedata++打开 保存即可!

  2. 『JavaScript』new关键字

    原文 new关键字做了什么 在JavaScript中,使用new关键字后,意味着做了如下四件事情: 创建一个新的对象,这个对象的类型是object: 设置这个新的对象的内部.可访问性和[[protot ...

  3. Leetcode代码补全——二叉树

    在刷leetcode的过程中发现,在原网页输入答案是不需要自己构筑树和链表的,虽然便于直接思考算法,但是久而久之类似过于依赖编辑器,反而不知道如何创建树和链表,因此总结了该网页省略的部分,以其中题为例 ...

  4. Tuxedo 通讯方式解析

    本节根据tuxedo自带samples的例子,让其运行起来.并通过这个例子,深入的理解tuxedo的通讯方式. 进入tuxedo的安装目录,samples目录下自带了一些例子 [root@localh ...

  5. 跳出for循环break和continue的区别

    1.break 跳出for循环,结束for循环 如果有两层循环,break只能跳出一层循环 2.continue 跳出本次循环,继续下一条数据的循环

  6. ubuntu 开热点

    原文地址:https://www.cnblogs.com/king-ding/archive/2016/10/09/ubuntuWIFI.html 今天教大家一个简单方法让ubuntu发散wifi热点 ...

  7. 第十三次ScrumMeeting会议

    第十三次Scrum Meeting 时间:2017/12/1 地点:咖啡馆 人员:策划组美工组 名字 完成的工作 计划工作 蔡帜 完成公式的基本策划,Bug数量产生机制设计 科技树方面机制确定 游心 ...

  8. 基于SDN的IP RAN网络虚拟化技术

    http://www.zte.com.cn/cndata/magazine/zte_technologies/2014/2014_4/magazine/201404/t20140421_422858. ...

  9. PAT 1005 继续(3n+1)猜想

    https://pintia.cn/problem-sets/994805260223102976/problems/994805320306507776 卡拉兹(Callatz)猜想已经在1001中 ...

  10. 【python】Python中给List添加元素的4种方法分享

    List 是 Python 中常用的数据类型,它一个有序集合,即其中的元素始终保持着初始时的定义的顺序(除非你对它们进行排序或其他修改操作). 在Python中,向List添加元素,方法有如下4种方法 ...