[NOIP2014] 解方程
题目描述
已知多项式方程:
求这个方程在 [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]);
}