[Noip2014] 解方程

题目描述

已知多项式方程: $$a_0+a_1x+a_2x^2+cdots+a_nx^n=0$$

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


输入输出格式

输入格式:

输入共 $n + 2$ 行。

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

接下来的 $n+1$ 行每行包含一个整数,依次为 $a_0,a_1,a_2ldots a_n$ 。

输出格式:

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

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


输入输出样例

输入样例#1: 
2 10 
1
-2
1
输出样例#1: 
1
1
输入样例#2: 
2 10
2
-3
1
输出样例#2: 
2
1
2
输入样例#3: 
2 10 
1  
3  
2  
 
输出样例#3: 
0

说明

对于 $30\%$ 的数据: $0<nle 2,|a_i|le 100,a_n≠0,m<100$ 。

对于 $50\%$ 的数据: $0<nle 100,|a_i|le 10^{100},a_n≠0,m<100$ 。

对于 $70\%$ 的数据: $0<nle 100,|a_i|le 10^{10000},a_n≠0,m<10^4$ 。

对于 $100\%$ 的数据: $0<nle 100,|a_i|le 10^{10000},a_n≠0,m<10^6$ 。


疯狂加美元符结果都没有用好伤心啊。

一看数据范围就知道这题一般的算法做不出来,这数据范围高精度过不去...

挣扎了一下午无望然后膜拜题解。

wow!这太神了。

这题要我在考场上绝对想不出来。

谁脑洞这么大想出取模的方法啊233了。

先把输入的$ large ai $对一个素数取模然后用秦九韶算。

我们设原函数为$ large f[] $。

那么$ large f[x]%p=0%p=0 $。

 所以取一个素数当模数就行了。

然而50分。

因为以上的算法冲突的概率是很大的, 解决方法就是多取几个模数。

然后70,剩下的TLE。

如何解决?

我们考虑,$ large f[x]%p!=0, f[x*k+b]%k!=0 $.

所以我们只需要求出1~mod-1的答案就行了。


#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
#define reg register
#define ll long long
#define int long long

int n, m;
int a[105][3];
bool can[1000004][3];
int p[3] = {23333, 23537, 15733};
char ch[10005];
int ans[1000005], cnt;

signed main()
{
    scanf("%lld%lld", &n, &m);
    for (reg int i = 0 ; i <= n ; i ++)
    {
        memset(ch, 0, sizeof ch);
        scanf("%s", ch + 1);
        int len = strlen(ch + 1);
        int tmp[3] = {0}, fu = 1;
        int j = 1;
        if (ch[1] == '-') fu = -1, j = 2;
        for (j ; j <= len ; j ++)
            for (reg int k = 0 ; k <= 2 ; k ++)
                tmp[k] = (tmp[k] * 10 + ch[j] - '0') % p[k];
        for (reg int k = 0 ; k <= 2 ; k ++)
        {
            a[i][k] = tmp[k];
            if (fu == -1) a[i][k] = p[k] - a[i][k];
        }
    }
    for (reg int i = 0 ; i <= mod ; i ++)
    {
        for (reg int k = 0 ; k <= 2 ; k ++)
        {
            ll sum = a[n][k];
            for (reg int j = n - 1 ; j >= 0 ; j --)
                sum = ((a[j][k] + sum * i) % p[k] + p[k]) % p[k];    
            if (!sum) can[i][k] = 1;
        }
    }
    for (reg int i = 1 ; i <= m ; i ++)
    {
        for (reg int k = 0 ; k <= 2 ; k ++)
            if (!can[i%p[k]][k])  goto End;
        ans[++cnt] = i;
        End:;
    }
    printf("%lld
", cnt);
    for (reg int i = 1 ; i <= cnt ; i ++)
        printf("%lld
", ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/BriMon/p/9525884.html