NOIP2014/洛谷P2312 解方程

题目描述

已知多项式方程:

a0+a1x+a2x^2+..+anx^n=0

求这个方程在[1, m ] 内的整数解(n 和m 均为正整数)

输入输出格式

输入格式:

输入文件名为equation .in。

输入共n + 2 行。

第一行包含2 个整数n 、m ,每两个整数之间用一个空格隔开。

接下来的n+1 行每行包含一个整数,依次为a0,a1,a2..an

输出格式:

输出文件名为equation .out 。

第一行输出方程在[1, m ] 内的整数解的个数。

接下来每行一个整数,按照从小到大的顺序依次输出方程在[1, m ] 内的一个整数解。

输入输出样例

输入样例#1: 复制
2 10 
1
-2
1
输出样例#1: 复制
1
1
输入样例#2: 复制
2 10
2
-3
1
输出样例#2: 复制
2
1
2
输入样例#3: 复制
2 10 
1  
3  
2  
 
输出样例#3: 复制
0

说明

对于30%的数据:0<n<=2,|ai|<=100,an!=0,m<100

对于50%的数据:0<n<=100,|ai|<=10^100,an!=0,m<100

对于70%的数据:0<n<=100,|ai|<=10^10000,an!=0,m<10000

对于100%的数据:0<n<=100,|ai|<=10^10000,an!=0,m<1000000

分析

对于30%的数据,用公式解就可以了。

对于50%的数据,高精度?

对于100%,m的范围不大,在这个范围内枚举,计算最后的值是否为0。要用到秦九韶算法,这样只需要做n次乘法,n次加法。但是a很大,高精度也很难表示怎么办?如果方程左面的值为0,那么方程两边同时mod一个值还是成立的。如果只mod一个值的话,答案很有可能不是正确的,因为如果这个值要是mod这个值的倍数的话,mod的值也是0。我们可以多mod几个值,那么这个数就必须满足是这几个值的最小公倍数的倍数才能在mod之后都为0,否则的话这个数就是0。但是前一种情况机率还是很小的,因为如果模数都取质数的话最小公倍数就是这几个数的乘积,还是很大的。但是这样的话时间复杂度是O(n*m)的,会超时的。如果一个数x mod p !=0 的话,那么x+p mod p!=0,这样就可以少计算一些无用的数。这样的话应该能通过官方数据。

关于秦九韶算法a[0]是否要乘以x,从公式上来看是不需要的,但是如果到最后结果如果是0的话就算乘以x之后还是0,对结果没有什么太大的影响,而且好记,代码短(lazy!)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1000010;
const int mo1=99991;
const int mo2=998244353;
const int mo3=1e9+7;
int n,m,cnt,a[N],b[N],c[N],ans[N]; bool vis[N];
inline void read(int i){
    ll x1=0,x2=0,x3=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){
        x1=(x1*10+ch-'0')%mo1;
        x2=(x2*10+ch-'0')%mo2;
        x3=(x3*10+ch-'0')%mo3;
        ch=getchar();
    }
    a[i]=x1*f;b[i]=x2*f;c[i]=x3*f;
}
inline bool calc1(int x){
    ll sum=0;
    for(int i=n;i>=0;--i)
        sum=((a[i]+sum)*x)%mo1;
    return !sum;
}
inline bool calc2(int x){
    ll sum1=0,sum2=0;
    for(int i=n;i>=0;--i){
        sum1=((b[i]+sum1)*x)%mo2;
        sum2=((c[i]+sum2)*x)%mo3;
    }
    return (!sum1)&&(!sum2);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<=n;++i) read(i);
    for(int i=1;i<=mo1;++i)
    if(calc1(i)){
        for(int j=i;j<=m;j+=mo1)
        if(calc2(j)) vis[j]=1;
    }
    for(int i=1;i<=m;++i) if(vis[i]) ans[++cnt]=i;
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;++i) printf("%d\n",ans[i]);
    return 0;
}

 

posted @ 2017-11-09 09:57  沐灵_hh  阅读(212)  评论(0编辑  收藏  举报