您的位置:首页 > 其它

Noip 2014 提高组 解方程

2017-08-09 09:51 309 查看

分析

观察发现如果直接暴力+高精度貌似只能拿50分。

这里运用了秦九韶算法。

一般地,一元n次多项式的求值需要经过2n-1次乘法和n次加法,而秦九韶算法只需要n次乘法和n次加法。在人工计算时,一次大大简化了运算过程。
把一个n次多项式



改写成如下形式:













多项式的值时,首先计算最内层括号内一次多项式的值,即





然后由内向外逐层计算一次多项式的值,即









这样,求n的多项式f(x)的值就转化为求n个一次多项式的值。
结论:对于一个n次多项式,至多做n次乘法和n次加法。

70分做法。

也就是不考虑数值的大小情况下,这道题变成了O(nm),是可以过的。

接下来可以考虑哈希,避免高精度计算,即把结果都模一个数,就可以过了。

为了保险可以多模几个数。

100分做法。

f(x) mod p≡f(x+p) mod p。

也就是说对于一个模数p,我们只需要处理出f(x) x∈[0,p-1]的值就可以O(1)判断f(x)是否是方程的解。

为了保险,多取几个模数。

时间复杂度为O(N*Σp+M)。

代码

#include<cstdio>//70分
using namespace std;

#define ll long long
#define M 1000000007

ll n,m,cnt;
ll ans[1000010],a[110];

ll max(ll a,ll b) {return a>b? a:b;}
ll min(ll a,ll b) {return a>b? b:a;}
void swap(ll &a,ll &b) {ll t=a;a=b;b=t;}

ll read()
{
ll x=0,f=1;char ch=getchar();
for (;ch>'9'||ch<'0';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x*10%M+ch-'0')%M;
return x*f;
}

ll check(ll h)
{
ll sum=0;
for (ll i=n;i>=0;i--)
sum=(sum*h%M+a[i])%M;
return sum;
}

int main()
{
n=read(); m=read();
for (ll i=0;i<=n;i++) a[i]=read();
for (ll i=1;i<=m;i++) if (check(i)==0) ans[++cnt]=i;
printf("%lld\n",cnt);
for (ll i=1;i<=cnt;i++) printf("%lld\n",ans[i]);
return 0;
}
#include<cstdio>//100分
using namespace std;

#define N 1000010
#define ll long long
ll f
[5],c
[5],n,m,cnt,ans
;
ll prime[5]={10007,11261,14843,19997,21893};

void read(ll x)
{
char ch=getchar();ll F=0;
for (;ch>'9' || ch<'0';ch=getchar()) if (ch=='-') F=1;
for (;ch>='0' && ch<='9';ch=getchar())
{
for (ll i=0;i<5;i++)
f[x][i]=(f[x][i]*10%prime[i]+ch-'0')%prime[i];
}
if (F)
for (ll i=0;i<5;i++) f[x][i]=prime[i]-f[x][i];
}

ll calc(ll x,ll y)
{
ll sum=0;
for (ll i=n;i>=0;i--)
sum=(sum*x%prime[y]+f[i][y])%prime[y];
return sum;
}

int main()
{
scanf("%d%d",&n,&m);
for (int i=0;i<=n;i++) read(i);
//	for (int i=0;i<=n;i++){for (int j=0;j<5;j++) printf("%d ",f[i][j]);puts("");}
for (int j=0;j<5;j++) for (int i=0;i<=prime[j];i++) c[i][j]=calc(i,j);
//	for ( i=0;i<=n;i++){for (ll j=0;j<5;j++) prllf("%d ",c[i][j]);puts("");}
for (ll i=1;i<=m;i++)
{
ll j; for (j=0;j<5;j++) if (c[i%prime[j]][j]) break;
if (j==5) ans[++cnt]=i;
}
printf("%d\n",cnt);
for (ll i=1;i<=cnt;i++) printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: