NOIP2014D2T3解方程

Posted cdcq(本博客废弃!现用博客:https://www.cn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP2014D2T3解方程相关的知识,希望对你有一定的参考价值。

神题一道,做了整整两天(其实是一个思路错了然后搞了两天QAQ)

原题:

已知多项式方程:a0+a1*x+a2*x^2+a3^x3+……+an^xn=0

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

0<n≤100,|ai|≤10^10000,an≠0,m≤1000000。

 

这题很神,首先部分分很足,高精度50,万进制或fft应该能拿70,然后正解的思路很奇怪(至少以我现在的水平看来是的)

思路就是如果一个数是0,呢么不管它膜什么数,结果都是0,我们就可以用这个性质来优化算方程的过程

呢么要枚举1-m,然后算,然而这样会T,就需要优化枚举的过程

如果一个数x%k=0,呢么(x+k)%k也是0,枚举的时候就只需要枚举到膜的数就可以代表后面的数

流程大概是酱紫的:

选择5-6个大质数(下面说的都是用5个质数的情况),在输入的时候直接输入数据就膜这五个大质数,然后分别存五个输入数据,表示这五个质数对应的输入数据

枚举内五个质数,然后枚举1-当前的质数,把枚举的东西丢进去算,如果等于零,这个答案就是合法的,否则不合法

如果这五质数搞出来的结果有一个不合法,枚举的东西就不合法

然而上面是这么说的↑,有一点需要注意,枚举的时候不能只用一个数组来+|(或&,都是位运算)来搞,需要先搞五个标记数组,分别对应丢进去算的数分别膜内五个大质数是否合法,在输出的时候再统一验证(即有一个不合法就不合法)

(就是这个问题↑卡了我整两天QAQ)

最后枚举1-m,然后枚举五个大质数,把i膜枚举的质数,然后看对应的标记数组里边是否合法,如果全合法,就进队(要输出个数)

这题脑洞好大……(也许是我太弱了)

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 int n,m;  int a[1100][10];
 8 bool can[1100000][6];
 9 int mo[6]={0,11261,19997,22877,21893,14843};
10 int dui[1100000],tou=0;
11 bool check(int x,int y){
12     int z=0;
13     for(int i=n;i>=1;i--)
14         z=((z+a[i][y])*x)%mo[y];
15     return ((z+a[0][y])%mo[y]) ? true : false;//因为memset的问题,所以这里#define false true
16 }
17 int main(){//freopen("ddd.in","r",stdin);
18     memset(can,0,sizeof(can));
19     memset(a,0,sizeof(a));
20     cin>>n>>m;
21     for(int i=0;i<=n;i++){
22         int mark=1;  char ch=getchar();
23         while(ch<\'0\'||ch>\'9\'){if(ch==\'-\')mark=-1;  ch=getchar();}
24         while(ch>=\'0\'&&ch<=\'9\'){
25             for(int j=1;j<=5;j++)
26                 a[i][j]=((a[i][j]<<3)+(a[i][j]<<1)+ch-\'0\')%mo[j];//边读边膜,而且要膜在check的时候膜的内个数
27             ch=getchar();
28         }
29         for(int j=1;j<=5;j++)
30             a[i][j]*=mark;
31     }
32     for(int j=1;j<=5;j++)
33         for(int i=1;i<=mo[j]&&i<=m;i++)//如果这个数膜膜的数合法,呢么它加上它膜的内个数也是合法的
34             can[i][j]=can[i][j] | check(i,j);
35     int i=1;
36     for(;i<=m;i++){
37         bool _can=false;
38         for(int j=1;j<=5;j++){
39             int temp=i%mo[j];
40             _can=_can | can[temp][j];
41         }
42         if(!_can)  dui[++tou]=i;
43     }
44     cout<<tou<<endl;
45     for(int i=1;i<=tou;i++)
46         printf("%d\\n",dui[i]);
47     return 0;
48 }
View Code

 

以上是关于NOIP2014D2T3解方程的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P2038 无线网络发射器选址(NOIp2014D2T1)

Vijos1910 NOIP2014提高组 Day2T3 解方程 其他

[luogu P3960] [noip2017 d2t3] 队列

NOIP2017D2T3 列队—Treap

[NOIP2017D2T3]列队

[CEOI2014D2T2] Cake [题解]