[NOIP2014] 解方程

题目描述

已知多项式方程:

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

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

输入输出格式

输入格式:

共 n+2行。

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

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

输出格式:

第一行输出方程在 [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<10^4\)
对于 100% 的数据:\(0<n≤100,∣a_i∣≤10^{10000},a_n≠0,m<10^6\)

Solution

首先我们得明白一条性质,如果我们选一个质数p,如果枚举x,发现多项式结果ans%p≠0,那么我们就能肯定x不是解,因为如果是解,那么多项式答案应该为0,但是0模任何数(除0之外)都为0,而此时发现模p不等于0,那么显然x不是解,看一波复杂度,O(NM)貌似可以过70分。继续想,
既然x不是解那么显然x+p也不是解,这样问题就解决了。
prime[i],代表第i个质数是什么。
但是又不能枚举去筛,那复杂度又上去了,所以可以用数组存下来,\(vis[i][j]\)代表i这个数取模第j个质数不等于0,那么到时枚举解x时,只需判断\(vis[x~~mod ~~prime[j]][j]\)是否等于0就行了,为了怕出错,多选几个质数就行了。
本题数据范围这么大,有点操蛋,这是要写高精度的节奏,死活不打。
发现可以一边读入一边取模。
这题数据有点强,卡1~200所有质数,所以我就选了一千多的质数。
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef unsigned long long ll;
char s[101][10010];
ll prime[]={2,7,9,11,103,1597,1601,1607,1609,1613,1619,1621,1627};
ll real[1010000],kzj=0;
ll p[110][20],vis[120][20];
ll ans[1001010];
ll check(char *ss,ll mod)
{
    ll flag=1,tot=0,x=0;char ch=ss[0];
    ll len=strlen(ss);
    if(ch<'0'||ch>'9') if(ch=='-') flag=-1,tot++,ch=ss[1];
    while(ch<='9'&&ch>='0') 
    {
        x=((x*10)%mod+(ch-48))%mod;
        ch=ss[++tot];
        if(tot==len)
        break;
    }
    return (x*flag+mod)%mod;
}
int main()
{   
//  freopen("xuanxue.in","r",stdin);
//  freopen("xuanxue.out","w",stdout);
    ll n,m;
    cin>>n>>m;
    n++;
    for(ll i=1;i<=n;i++)
    scanf("%s",s[i]);
    for(ll i=1;i<=n;i++)
    {
        for(ll j=0;j<=12;j++)
        p[i][j]=check(s[i],prime[j]);
    }
    for(ll i=1;i<=1700;i++)
    {
        ll flag=0;
        for(ll j=0;j<=12;j++)
        {
            ll k=1,sum=0;
            ll mod=prime[j];
            for(ll t=1;t<=n;t++)
            {
                sum=(sum%mod+p[t][j]%mod*k%mod)%mod;    
                k=k*i%mod;
            }
            if(sum!=0) 
            {
                vis[i][j]=1;
            }
        }
    }
    for(ll i=1;i<=m;i++)
    {
        ll flag=0;
        for(ll j=0;j<=12;j++)
        if(vis[i%prime[j]][j]==1)
        flag=1;
        if(!flag) real[++kzj]=i;
    }
    cout<<kzj<<endl;
    for(ll i=1;i<=kzj;i++)
    printf("%lld\n",real[i]);
}

猜你喜欢

转载自www.cnblogs.com/kzj-pwq/p/9567313.html
今日推荐