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; }
相关文章推荐
- 解方程 NOIP2014 提高组 Day2 T3
- 【NOIP提高组2014】解方程
- [NOIP2014] 提高组 洛谷P2312 解方程
- NOIP2014复赛提高组day2(A:无线网络发射器选址 B:寻找道路 C:解方程)
- [NOIp2014提高组]解方程
- 【NOIP】提高组2014 解方程
- [解题报告] NOIP 2014 提高组Day2试题
- Noip2014 Day2 T3 解方程(数论+取模运算)
- NOIP 2014 - 提高组 寻找道路
- NOIP2014提高组DAY1题解
- 无线网络发射选址 NOIP2014 提高组 Day2 T1
- NOIP 2014 解方程 [模运算][哈希?]
- 【NOIP2014】解方程
- 【noip 2014】提高组Day2T3.华容道
- NOIp 2014 解方程 【数学/秦九韶算法/大数取膜】By cellur925
- 2014 Noip提高组 Day1
- noip2014 提高组题解 bird
- [NOIP2014] 提高组 洛谷P1328 生活大爆炸版石头剪刀布
- 【noip2014提高组】飞扬的小鸟
- bzoj 3751: [NOIP2014]解方程