NOIp2014Day2T3 解方程

题目分析:

如果直接使用秦九昭算法+高精度显然会TLE。

我们想到,多项式f(x)=0,则f(x)≡0(mod p),p∈R,所以我们可以选取几个数p,让1到m的数x分别在模pi的意义下进行秦九昭算法,只有对于所有的p,多项式的值为0时,x才可能为一个根。

该算法很容易由于p选取不当而错,所以这里p最好多取一些质数。

如上,算法复杂度为O(nm)。

优化:

由于我们是在模的意义下求解的,所以,多项式存在如下性质:

f(x) mod p=f(x mod p) mod p

我们发现,从1到m枚举x是没有价值的,因为存在大量重复计算。我们只要从1到max{pi}枚举x,对f(x) mod pi=0的x打上标记。再从1到m枚举x,只有对于每个p,x均被标记时,x才可能为一个根。

如上,算法复杂度为O(n*max{pi}+m)

扩展:

1元n次多项式f(x)=0的有理根一定能够表示成p/q的形式。其中p是常数项的约数,q是n次项的约数。

然而这条性质在这题貌似没有什么用。

代码细节:

没什么细节,请参考代码部分。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 #define index gddgf
 8 
 9 //constant//
10 const int N=10;
11 const int mod[N]={9973,9931,9941,9949,9967,9833,9839,9851,9857,9859};
12 
13 //variable//
14 char str[10010];
15 int a[N][110],n,m,ans[110],tot=0,index[110],vis[N][110000];
16 
17 //solve//
18 int main(){
19     scanf("%d%d",&n,&m);cin.get();
20     for (int i=0;i<=n;++i){
21         scanf("%c",&str[0]);
22         if (str[0]=='-'){
23             index[i]=-1;
24             gets(str);
25         }else{
26             index[i]=1;
27             gets(str+1);
28         }
29         int len=strlen(str);
30         for (int j=0;j<len;++j){
31             for (int k=0;k<N;++k){
32                 a[k][i]=(a[k][i]*10+str[j]-'0')%mod[k];
33             }
34         }
35     }
36     for (int x=1;x<=mod[0];++x){
37         long long s[N]={0};
38         for (int i=n;i>=0;--i){
39             for (int j=0;j<N;++j){
40                 s[j]=((s[j]*(long long)x)%mod[j]+(long long)a[j][i]*index[i])%mod[j];
41             }
42         }
43         for (int i=0;i<N;++i){
44             vis[i][x%mod[i]]=(s[i]==0);
45         }
46     }
47     for (int x=1;x<=m;++x){
48         bool flag=true;
49         for (int i=0;i<N;++i){
50             if (!vis[i][x%mod[i]]){
51                 flag=false;
52                 break;
53             }
54         }
55         if (flag){
56             ans[++tot]=x;
57         }
58     }
59     printf("%d\n",tot);
60     for (int i=1;i<=tot;++i){
61         printf("%d\n",ans[i]);
62     }
63     return 0;
64 }
View Code

 

转载于:https://www.cnblogs.com/ZXTLFDeAR/p/4797647.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值