NOIP2014 解方程

NOIP2014 解方程

Description

img

Input

输入文件名为equation.in。

输入共n+2行。

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

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

Output

输出文件名为equation.out。

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

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

Sample Input

输入样例#1:

2 10

1

-2

1

输入样例#2:

2 10

2

-3

1

输入样例#3:

2 10

1

3

2

Sample Output

输出样例#1:

1

1

输出样例#2:

2

1

2

输出样例#3:

0

Hint

img

Solution:

这题什么鬼,看到解方程还是第三题直接吓尿好吧...

感觉哈希比较像正解。然而害怕并不是很靠谱,于是敲完了30%的long long和50%的高精,就写了个哈希放在了那里,测了一下极限数据都快要三秒了,于是就加上了双哈希。(233)

然而正解真的是哈希…(这么玄学真的好吗

对于 f(x)%P=0 ,我们认为 f(x)=0 的可能性是非常大的,然后注意到式子里只有加法与幂运算:如果 xn0(modP) ,则 (x+P)n0(modP) 。则如果 f(x)0(modP) ,有 f(x+P)0(modP)

于是取几个小素数 P ,计算出[0,P)的函数值,对于 [1,m] 的数 x ,对于我们的每一个素数P,如果都有 f(x%P)=0 f <script type="math/tex" id="MathJax-Element-13">f</script>数组已预先处理好),那么我们就认为这个数是方程的解。

当然如果不放心,可以再用一个大素数依次检验一下筛选出来的数。

#include<ctime>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<vector>
#define ll long long
#define mp make_pair
#define pb push_back
#define pll pair<ll,ll>
#define pii pair<int,int>
#define lson (p<<1)
#define rson (p<<1|1)
#define lowbit(x) (x&(-x))
#define siz(x) ((x).size())
using namespace std;
const int M=105;
const int Len=20005;
int n,m;
int f[5]={9227,10007,10009,9281,7741};
char str[Len];
int A[5][M],rs[5][Len],Ans[1000005],sz;
int calc(int x,int i){
    int x0=1,sum=0;
    for(int j=0;j<=n;j++){
        sum=(sum+x0*A[i][j])%f[i];
        x0=x0*x%f[i];
    }
    return sum;
}
bool check(int x){
    for(int i=0;i<5;i++)
        if(rs[i][x%f[i]]!=0)return false;
    return true;
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=0;i<=n;i++){
        scanf("%s",str+1);
        int len=strlen(str+1);
        for(int j=0;j<5;j++){
            int k=1;
            if(str[k]=='-')k++;
            for(;k<=len;k++){
                A[j][i]=(A[j][i]*10+(str[k]^48))%f[j];
            }
            if(str[1]=='-')A[j][i]=-A[j][i];
        }
    }
    for(int i=0;i<5;i++)
        for(int j=0;j<f[i];j++)
            rs[i][j]=calc(j,i);
    for(int i=1;i<=m;i++)
        if(check(i))Ans[++sz]=i;
    printf("%d\n",sz);
    for(int i=1;i<=sz;i++)
        printf("%d\n",Ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值