1. 程式人生 > 實用技巧 >BZOJ-3751[NOIP2014]解方程(秦久韶演算法+hash)

BZOJ-3751[NOIP2014]解方程(秦久韶演算法+hash)

題目描述

  已知多項式方程:

\[a_0+a_1x+a_2x^2+\cdots+a_nx^n=0 \]

  求這個方程在 \([1,m]\) 內的整數解(\(0<n\leq 100,|a_i|\leq 10^{10000},a_n\neq 0,m<10^6\))。

分析

  根據秦九韶演算法:

\[\begin{aligned}&A(x)\\=&a_nx^n+a_{n-1}x^{n-1}+\cdots+a_1x+a_0\\ =&(a_nx^{n-1}+a_{n-1}x^{n-2}+\cdots+a_2x+a_1)x+a_0\\ =&((a_nx^{n-2}+a_{n-3}x^{n-2}+\cdots+a_3x+a_2)x+a_1)x+a_0\\ =&(\cdots((a_nx+a_{n-1})x+a_{n-2})x+\cdots+a_1)x+a_0 \end{aligned} \]

  由內向外逐層計算一次多項式的值。

  \(a_i\) 非常大,將其對一個大質數取模(比如 \(998244353\)),由於 \(A(x)=0\),則 \(A(x)\equiv 0\pmod {p}\),所以取模後用秦久韶演算法再檢驗是正確的(為了防止雜湊衝突可以多選幾個模數)。

程式碼

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
inline long long read()
{
    long long x=0,f=1;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)){x=(x*10%mod+ch-48)%mod;ch=getchar();}
    return x*f;
}
long long n,m,cnt;
long long a[1000010],ans[1000010];
bool check(long long x)
{
    long long ans=0;
    for(int i=n;i>=1;i--)
        ans=(ans+a[i])*x%mod;
    ans=(ans+a[0])%mod;
    if(ans==0)
        return true;
    return false;
}
int main()
{
    bool flag=false;
    n=read();m=read();
    for(int i=0;i<=n;i++)
        a[i]=read();
    for(int i=1;i<=m;i++)
    {
        if(check(i))
        {
            ans[++cnt]=i;
            flag=true;
        }
    }
    if(!flag)
    {
        puts("0");
        return 0;
    }
    cout<<cnt<<endl;
    for(int i=1;i<=cnt;i++)
        printf("%lld\n",ans[i]);
    return 0;
}