BZOJ3751 [NOIP2014]解方程

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

 

 

 

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

 

 

Description

 已知多项式方程:

a0+a1*x+a2*x^2+...+an*x^n=0
求这个方程在[1,m]内的整数解(n和m均为正整数)。
 

Input

第一行包含2个整数n、m,每两个整数之间用一个空格隔开。
接下来的n+1行每行包含一个整数,依次为a0,a1,a2,...,an。

Output

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

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

Sample Input

2 10
2
-3
1

Sample Output

2
1
2

HINT 

 对于100%的数据,0<n≤100,|ai|≤1010000,an≠0,m≤1000000。

 

 

正解:模意义下相等

解题报告:

  这道题的画风可以说是NOIP的day2T3中最奇怪的了,算法简单,只是谁想得到联赛T3考这种题目...

  首先可以明确,假设本来某个x就成立,那么我把系数和x的次幂都取一个模,这个式子同样成立。所以考虑取几个模数,然后对于式子整体取模,并且检验,如果都等于0我们就可以视为原式相等。

  但是这个做法只有70分。考虑如何优化,因为如果x大于模数,那么可以发现x+p再代入原式,得到的答案没有任何区别,所以我们可以把模数取小一点,为了保证正确率,模数取多一点,然后我们只对于每个模数检验0到模数-1,因为大了就没有意义了。这样的做法可以获得100分。但是模数要取得好,我试了很久,发现最少要取3个,少了就肯定会错了...

 

 1 //It is made by ljh2000
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 using namespace std;
14 typedef long long LL;
15 #define RG register
16 const int MAXN = 50011;
17 int n,m,len,pcnt=2,prime[12]={23333,22877,19997};
18 int a[12][MAXN],now_ans,xx,ss,ans[12][MAXN],cnt,dui[1000011];
19 char ch[10011];
20 bool fu[150];
21 
22 inline int getint()
23 {
24     int w=0,q=0; char c=getchar();
25     while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 
26     while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w;
27 }
28 
29 inline bool check(RG int x){
30     for(RG int i=0;i<=pcnt;i++)
31     if(ans[i][x%prime[i]]!=0)  return false;
32     return true;
33 }
34 
35 inline void work(){
36     n=getint(); m=getint(); 
37     for(RG int i=0;i<=n;i++) {//读入第i个系数
38     scanf("%s",ch); len=strlen(ch); if(ch[0]=='-') fu[i]=1;
39     for(RG int o=0;o<=pcnt;o++) {//分别求出对于每个模数意义下的系数的实际值
40         ss=1;
41         for(RG int j=len-1;j>=1;j--) {          
42         a[o][i]+=(ch[j]-'0')*ss; a[o][i]%=prime[o];
43         ss*=10; ss%=prime[o];
44         }        
45         if(fu[i]==0) { a[o][i]+=(ch[0]-'0')*ss; a[o][i]%=prime[o]; ss*=10; ss%=prime[o]; }
46     }
47     }
48     for(RG int i=0;i<=pcnt;i++) {
49     for(RG int x=0;x<prime[i];x++) {        
50         xx=1; now_ans=0;
51         for(RG int j=0;j<=n;j++) {        
52         if(fu[j]) now_ans-=xx*a[i][j]; else now_ans+=xx*a[i][j]; 
53         now_ans%=prime[i];       
54         xx*=x; xx%=prime[i];
55         }
56         ans[i][x]=now_ans;
57     }
58     }
59     for(RG int i=1;i<=m;i++) if(check(i)) dui[++cnt]=i;
60     printf("%d\n",cnt);
61     for(RG int i=1;i<=cnt;i++) printf("%d\n",dui[i]);
62 }
63 
64 int main()
65 {
66     work();
67     return 0;
68 }

 

 

转载于:https://www.cnblogs.com/ljh2000-jump/p/6059182.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值