码迷,mamicode.com
首页 > 其他好文 > 详细

noip2014 解方程

时间:2016-08-11 19:19:28      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:

P2312 解方程

    • 206通过
    • 1.7K提交
  • 题目提供者该用户不存在
  • 标签数论(数学相关)高精2014NOIp提高组
  • 难度提高+/省选-

提交该题 讨论 题解 记录

最新讨论

题目描述

已知多项式方程:

a0+a1x+a2x^2+..+anx^n=0

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

输入输出格式

输入格式:

 

输入文件名为equation .in。

输入共n + 2 行。

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

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

 

输出格式:

 

输出文件名为equation .out 。

第一行输出方程在[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,|ai|<=100,an!=0,m<100

50%:0<n<=100,|ai|<=10^100,an!=0,m<100

70%:0<n<=100,|ai|<=10^10000,an!=0,m<10000

100%:0<n<=100,|ai|<=10^10000,an!=0,m<1000000

分析:很久以前,阿贝尔证明过一元n次方程(n >= 5)是没有求根公式的,似乎只有30%的数据可以暴力求,怎么样才能AC呢?那就要做到缩小数据.可以注意到ai和m非常大,m似乎不能缩了,那ai怎么缩呢?注意到这是一个方程,那么就是取模运算了,因为要使方程的结果等于0,如果f(x) == 0,那么f(x) mod p == 0,但是逆定理不一定成立,但是如果多枚举几个p的话AC的可能性就比较大,少枚举会WA,枚举大了会TLE,这就是看脸的时候了,这个时候取一个10000左右的质数和一个比较大的质数 (大于m)即可,为什么要取质数呢?如果ai等于0那么就没有意义了.难道要一个一个枚举x吗?这样未免太慢了,注意到如果f(x) mod p == 0,那么f(x + p) mod p = f(x) mod p + p mod p == 0,所以我们在x的基础上不断的加p即可.在计算的时候一旦有可能超过p,就mod.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

char s[10010];
int p[3], n, m;
long long a[3][105];
bool can[1000010];

void quyu(char *s1, int k)
{
    bool fu = false;
    int len = strlen(s1), i;
    for (int j = 1; j <= 2; j++)
    {
        i = 0;
        if (s1[0] == -)
        {
            fu = true;
            i = 1;
        }
        for (; i < len; i++)
            a[j][k] = (a[j][k] * 10LL % p[j] + s[i] - 0) % p[j];
        if (fu == true)
            a[j][k] = p[j] - a[j][k];
    }
}

int panduan(int x, int k)
{
    long long ans = 0, b = 1;
    for (int i = 0; i <= n; i++)
    {
        ans = (ans + 1LL * a[k][i] * b) % p[k];
        b = 1LL * b * x % p[k];
    }
    return ans % p[k];
}

int main()
{
    p[1] = 67891, p[2] = 1000000207;  //两个质数
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++)
        can[i] = false;
    for (int i = 0; i <= n; i++)
    {
        scanf("%s", s);
        quyu(s, i);           
    }
    for (int i = 1; i <= p[1]; i++)
    {
        if (panduan(i, 1) != 0)
            continue;
        for (int j = i; j <= m; j += p[1])
            if (panduan(j, 2) == 0)
                can[j] = true;
    }
    int ans = 0;
    for (int i = 1; i <= m; i++)
        if (can[i])
            ans++;
    printf("%d\n", ans);
    for (int i = 1; i <= m; i++)
        if (can[i])
            printf("%d\n", i);

    return 0;
}

 

noip2014 解方程

标签:

原文地址:http://www.cnblogs.com/zbtrs/p/5762077.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!