【NOIP提高组2014】解方程

版权声明:本文为博主原创文章……懂吗?要尊重别人的劳动成果呐 https://blog.csdn.net/Tiw_Air_Op1721/article/details/82381653

@解方程@


@题目描述@

已知多项式方程:

a 0 + a 1 x + a 2 x 2 + . . . + a n x n = 0

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

输入
输入共 n + 2 行。
第一行包含 2 个整数 n , m , 每两个整数之间用一个空格隔开。
接下来的 n+1 行每行包含一个整数,依次为 a 0 , a 1 , a 2 . . . 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 < n 2 , | a i | 100 , a n 0 , m < 100
对于 50 % 的数据: 0 < n 100 , | a i | 10 100 , a n 0 , m < 100
对于 70 % 的数据: 0 < n 100 , | a i | 10 10000 , a n 0 , m < 10000
对于 100 % 的数据: 0 < n 100 , | a i | 10 10000 , a n 0 , m < 1000000

@分析1 - 30%数据@

因为根的范围不是很大,我们可以逐个枚举根的值,代入多项式中判断是否合法。

@分析2 - 50%数据@

写高精度。注意多项式求值可以用秦九韶算法(霍纳算法):

a 0 + a 1 x + . . . + a n x n = ( a 0 + x ( a 1 + x ( a 2... ( a n 1 + a n x )

从内往外算,可以只做O(n)次的高精度加法与O(n)次的高精度乘低精度

@分析3 - 70%数据@

【我太弱了只能想到50%……高精度最后还写WA了……QAQ】
可以使用哈希将值域范围缩小。
具体来说,将整个多项式对某个质数p取模,得到

a 0 + a 1 x + a 2 x 2 + . . . + a n x n = 0 mod p

a i = a i mod p ,则有:

a 0 + a 1 x + a 2 x 2 + . . . + a n x n = 0 mod p

我们就省去了作高精度乘法的时间复杂度。然而因为哈希是不确定性算法,所以我们需要多选几个模数。

为什么这样正确性高?考虑这样一个事实:
p 1 p 2 a = k mod p 1 a = k mod p 2 a = k mod p 1 p 2
因此,假如我选了5个10^9级别的质数作为哈希的模数,那么只有当表达式的值被一个10^45次方级别的数整除时,算法才会出错。
然而因为我这5个数是随机选的,加上出题人不会针对你的程序造反例,所以除非你是非酋中的非酋,否则你是不会因为哈希WA掉的。
理论时间复杂度 O ( n m P ) ,P 是你选择的模数个数。

@分析4 - 100%数据@

上面的程序在某些数据水的OJ上甚至能AC。。。
然而如果卡起常来可能就会TLE。。。
我们需要优化。
有这样一个事实: f ( x ) mod p = f ( x mod p ) mod p
因此我们只需要求解出x=[0, p-1]对应的多项式值就可以了。如果我们把模数 p 调到比 m 小,则时间将会快很多。

然而因为你把模数调小了,所以要多选几个模数以保证正确性。
理论时间复杂度 O ( m P M a x M o d ) ,P 是你选择的模数个数,MaxMod是最大的模数值。

@代码@

我果然还是个蒟蒻了QAQ

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int MAXN = 100;
const int MAXS = 10000;
const int MOD[5] = {2003, 2011, 2017, 2027, 2029};
int a[5][MAXN + 5];
int res[5][3000];
vector<int>ans;
char s[MAXS + 5];
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i=0;i<=n;i++) {
        scanf("%s", s);
        int len = strlen(s);
        if( s[0] == '-' ) {
            for(int k=0;k<5;k++) {
                for(int j=1;j<len;j++)
                    a[k][i] = (a[k][i] * 10 + s[j]-'0') % MOD[k];
                a[k][i] *= -1;
            }
        }
        else {
            for(int k=0;k<5;k++) {
                for(int j=0;j<len;j++)
                    a[k][i] = (a[k][i] * 10 + s[j]-'0')% MOD[k];
            }
        }
    }
    for(int i=0;i<5;i++) {
        for(int j=0;j<MOD[i];j++) {
            res[i][j] = a[i][n];
            for(int k=n-1;k>=0;k--)
                res[i][j] = (res[i][j]*j + a[i][k]) % MOD[i];
        }
    }
    for(int i=1;i<=m;i++) {
        bool flag = true;
        for(int j=0;j<5;j++) {
            if( res[j][i%MOD[j]] ) flag = false;
        }
        if( flag ) ans.push_back(i);
    }
    printf("%d\n", ans.size());
    for(int i=0;i<ans.size();i++)
        printf("%d\n", ans[i]);
}

@END@

就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。~

猜你喜欢

转载自blog.csdn.net/Tiw_Air_Op1721/article/details/82381653
今日推荐