「NOIP 2014 D2T3」解方程

传送门


problem

已知多项式方程:

a 0 + a 1 x + a 2 x 2 + ⋯ + a n x n = 0 a_0+a_1x+a_2x^2+\cdots+a_nx^n=0 a0+a1x+a2x2++anxn=0

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

数据范围: 0 < n ≤ 100 0<n\le 100 0<n100 ∣ a i ∣ ≤ 1 0 10000 |a_i|\le 10^{10000} ai1010000 a n ≠ 0 a_n≠0 an=0 m < 1 0 6 m<10^6 m<106


solution

怎么感觉 14 年的题都挺简单的。。

这道题主要就是两个问题。

1 1 1 a i a_i ai 过大,怎么处理?

a i a_i ai 取模,转换成模意义下的计算。

如果觉得不保险就多对几个数取模,不过对于此题用 1 0 9 + 7 10^9+7 109+7 就够了。

2 2 2、如何比较快速地求一个多项式的值?

这个就直接用秦九昭算法暴力展开就好了,即:

f ( x ) = a n x n + a n − 1 x n − 1 + ⋯ + a 1 x + a 0 = ( a n x n − 1 + a n − 1 x n − 2 + ⋯ + a 2 x + a 1 ) x + a 0 = ( ( a n x n − 2 + a n − 1 x n − 3 + ⋯ + a 3 x + a 2 ) x + a 1 ) x + a 0      ⋮ = ( ⋯ ( a n x + a n − 1 ) x + ⋯ + a 1 ) x + a 0 \begin{aligned} f(x)&=a_nx^n+a_{n-1}x^{n-1}+\cdots+a_1x+a_0\\ &=(a_nx^{n-1}+a_{n-1}x^{n-2}+\cdots+a_2x+a_1)x+a_0\\ &=((a_nx^{n-2}+a_{n-1}x^{n-3}+\cdots+a_3x+a_2)x+a_1)x+a_0\\ &\;\;\vdots\\ &=(\cdots(a_nx+a_{n-1})x+\cdots+a_1)x+a_0 \end{aligned} f(x)=anxn+an1xn1++a1x+a0=(anxn1+an1xn2++a2x+a1)x+a0=((anxn2+an1xn3++a3x+a2)x+a1)x+a0=((anx+an1)x++a1)x+a0

那么我们就可以在 O ( n ) O(n) O(n) 的时间内计算出一个点 x x x f ( x ) f(x) f(x) 值。

然后直接枚举 ∀ i ∈ [ 1 , m ] \forall i\in[1,m] i[1,m],暴力验证即可。

时间复杂度 O ( n m ) O(nm) O(nm),但是常数小能过。


code

#include<bits/stdc++.h>
#define P 1000000007
using namespace std;
int add(int x,int y)  {return x+y>=P?x+y-P:x+y;}
int dec(int x,int y)  {return x-y< 0?x-y+P:x-y;}
int mul(int x,int y)  {return 1ll*x*y%P;}
namespace IO{
	const int Rlen=1<<22|1;
	char buf[Rlen],*p1,*p2;
	inline char gc(){
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>
	inline T Read(){
		T x=0,f=1;char c=gc();
		while(!isdigit(c)&&c!='-')  c=gc();
		if(c=='-')  f=0,c=gc();
		while(isdigit(c))  x=add(mul(10,x),c^48),c=gc();
		return f?x:(P-x);
	}
	inline int in()  {return Read<int>();}
	inline void out(int x){
		if(x>9)  out(x/10);
		putchar(x%10+'0');
	}
}
using IO::in;
using IO::out;
int n,m,tot,a[105],ans[1000005];
int calc(int x){
	int val=0;
	for(int i=n;i>=1;--i)  val=mul(add(a[i],val),x);
	return add(val,a[0]);
}
int main(){
	n=in(),m=in();
	for(int i=0;i<=n;++i)  a[i]=in();
	for(int i=1;i<=m;++i)  if(!calc(i))  ans[++tot]=i;
	out(tot),putchar('\n');
	for(int i=1;i<=tot;++i)  out(ans[i]),putchar('\n');
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值