NOIP 2014 解方程 Hash Hash Hash

hash,同余类,hash,同余类,hash,同余类。先默念三遍。简直神器。
这个多项式方程每个系数都是1w位的数,一看就知道必须要取模。70分做法就是取模,直接暴力算每个数是不是解,模的数好的情况下可以拿70,T3个点。

怎么过这三个点呢?多项式方程f(x)是满足f(x) % p == f(x+p) % p的,这也是上述70分做法成立的原因。正解就是对于p的每个同余类,判断是否为解,如果x为解,x+p同样为解。但这是在模p意义下的,既然我们在每个同余类中计算来节省时间,p就不能太大,为了保证正确性,我们可以多取几个p,同时满足才为解。根据算法复杂度计算,p取sqrt(nm)附近时是比较优的。

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

int n, m, num, a[6][105];
int P[6] = {0, 10007, 10093, 10957, 12917, 13187};
char s[10005];
bool ok[1000005];

int f(int x, int mod)
{
    int res = 0; x %= P[mod];
    for(int i = 0, j = 1; i <= n; i++)
    {
        res = (res+a[mod][i]*j%P[mod])%P[mod];
        j = j * x % P[mod];
    }
    return res;
}

bool judge(int x)
{
    for(int i = 2; i <= 5; i++)
        if(f(x, i)) return 0;
    return 1;
}

int main()
{
    scanf("%d %d", &n, &m);
    for(int i = 0; i <= n; i++)
    {
        scanf("%s", s+1);
        int k = 1; bool neg = 0;
        if(s[k] == '-') neg = 1, k++;
        for(int j = 1; j <= 5; j++)
        {
            int t = k; 
            while(s[t]) a[j][i] = (a[j][i]*10+s[t++]-48)%P[j];
            if(neg) a[j][i] = -a[j][i];
        }
    }

    for(int i = 1; i <= min(P[1], m); i++) if(!f(i, 1))
    {
        ok[i] = 1, num++;   
        int t = i;
        while(t+P[1] <= m) ok[t+=P[1]] = 1, num++;
    } 

    for(int i = 1; i <= m; i++) 
        if(ok[i] && !judge(i)) ok[i] = 0, num--;

    printf("%d\n", num);
    for(int i = 1; i <= m; i++) 
        if(ok[i]) printf("%d \n", i);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值