洛谷 P2312 解方程
首先,可以确定的是这题的做法就是暴力枚举x,然后去计算方程左边与右边是否相等。
但是noip的D2T3怎么会真的这么简单呢?卡常卡的真是熟练 你需要一些优化方法。
首先可以用秦九韶公式优化一下方程左边的计算方法:
左边=(((..(a[n]*x)+a[n-1])*x+..+a[1])*x+a[0]
然后我就试着直接去算:
#include<cstdio>
typedef long long LL;
LL a[110],ans[1001000];
LL n,m,aa;
int main()
{
LL i,j;
scanf("%lld%lld",&n,&m);
for(i=0;i<=n;i++)
scanf("%lld",&a[i]);
for(i=n;i>=1;i--)
for(j=1;j<=m;j++)
{
ans[j]+=a[i];
ans[j]*=j;
}
for(i=1;i<=m;i++)
ans[i]+=a[0];
for(i=1;i<=m;i++)
if(ans[i]==0)
aa++;
printf("%lld\n",aa);
for(i=1;i<=m;i++)
if(ans[i]==0)
printf("%lld\n",i);
return 0;
}
然后就Wa(30)掉了...没看清数据范围(ai最长有10000位,而不是最大10000)
也许你会想到高精度运算,但是很容易发现,这题的数据范围太大,直接高精度暴力算太慢。
此时有一个小trick:对于每个a[n],读入的时候对某一些大质数取模。对于每个枚举出的x,就用取模过的a[i]去算。如果用对好几组对不同质数取模得到的a[i]算都能得到0,那么就认为x是合法的。
直觉上可能觉得很容易被卡掉?但事实上一点也不容易被卡....好像还是正解..
那么对于负的a[i]怎么去取模呢?很简单,读入的时候看一下符号位,然后按照正数的方式取模(每读入一位将当前余数乘10再加当前位再取模)。处理完整个数后,如果记录的符号位是负数,那么就将余数变为模数-余数。
然后我去交...然后就T(70)掉了...还是太慢。(而且O2都救不了我...)
//#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
typedef long long LL;
LL a[5][110],ans[5][1001000];
LL prime[]={179424629,179424667,179424671,179424673,179424691};
LL pnum=5,n,m,aa;
char c;
bool nok[1010000];
int main()
{
//freopen("testdata.in","r",stdin);
//freopen("testdata.ss","w",stdout);
LL i,j,i1,fl,sl,p;
scanf("%lld%lld",&n,&m);
c=getchar();
for(i=0;i<=n;i++)
{
while(!((c>='0'&&c<='9')||c=='-')) c=getchar();
if(c=='-')
fl=1,c=getchar();
else
fl=0;
for(j=0;j<pnum;j++)
{
for(i1=fl;c>='0'&&c<='9';i1++)
{
a[j][i]=(a[j][i]*10+c-'0');
while(a[j][i]>=prime[j]) a[j][i]-=prime[j];
//ans[j][i]-=prime[j]
c=getchar();
}
if(fl) a[j][i]=prime[j]-a[j][i];
}
}
for(p=0;p<pnum;p++)
{
for(j=1;j<=m;j++)
if(!nok[j])
for(i=n;i>=1;i--)
{
ans[p][j]=(ans[p][j]+a[p][i])*j%prime[p];
}
for(j=1;j<=m;j++)
if(!nok[j])
{
ans[p][j]+=a[p][0];
while(ans[p][j]>=prime[p]) ans[p][j]-=prime[p];
}
for(j=1;j<=m;j++)
if(ans[p][j]!=0)
nok[j]=1;
}
for(i=1;i<=m;i++)
if(!nok[i])
aa++;
printf("%lld\n",aa);
for(i=1;i<=m;i++)
if(!nok[i])
printf("%lld\n",i);
return 0;
}
卡了很久的常之后,我放弃了,去看了题解。
原来这个算法是可以接着优化的:http://www.cnblogs.com/NaVi-Awson/p/7566889.html
根据的就是:f(x)≡0(modp),则f(x+p)≡0(modp)
这样子可以快速过滤掉一些m。(怎么觉得是卡常呢...)
然后,我又去交..又T(70)了..
原因:质数选的太大,这样是不能筛掉什么m的
#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
typedef long long LL;
LL a[5][110],ans[5][1001000];
LL prime[]={179424629,179424667,179424671,179424673,179424691};
LL pnum=5,n,m,aa;
char c;
bool nok[1010000];
int main()
{
//freopen("testdata.in","r",stdin);
//freopen("testdata.ss","w",stdout);
LL i,j,i1,fl,sl,p,k;
scanf("%lld%lld",&n,&m);
c=getchar();
for(i=0;i<=n;i++)
{
while(!((c>='0'&&c<='9')||c=='-')) c=getchar();
if(c=='-')
fl=1,c=getchar();
else
fl=0;
for(j=0;j<pnum;j++)
{
for(i1=fl;c>='0'&&c<='9';i1++)
{
a[j][i]=(a[j][i]*10+c-'0');
while(a[j][i]>=prime[j]) a[j][i]-=prime[j];
//ans[j][i]-=prime[j]
c=getchar();
}
if(fl) a[j][i]=prime[j]-a[j][i];
}
}
for(p=0;p<pnum;p++)
{
for(j=1;j<=m;j++)
if(!nok[j])
{
for(i=n;i>=1;i--)
ans[p][j]=(ans[p][j]+a[p][i])*j%prime[p];
ans[p][j]+=a[p][0];
while(ans[p][j]>=prime[p]) ans[p][j]-=prime[p];
if(ans[p][j]!=0)
for(k=j;k<=m;k+=prime[p])
nok[k]=1;
}
}
for(i=1;i<=m;i++)
if(!nok[i])
aa++;
printf("%lld\n",aa);
for(i=1;i<=m;i++)
if(!nok[i])
printf("%lld\n",i);
return 0;
}
改进:可以用比较小的质数筛掉大部分m,然后用大质数筛掉剩下(也许存在的)不合法的m。
AC代码:
//#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
typedef long long LL;
LL a[5][110],ans[5][1001000];
LL prime[]={81799,81817,179424671,179424673,179424691};
LL pnum=5,n,m,aa;
char s[10100];
bool nok[1010000];
int main()
{
//freopen("testdata.in","r",stdin);
//freopen("testdata.ss","w",stdout);
LL i,j,i1,fl,sl,p,k;
scanf("%lld%lld",&n,&m);
// c=getchar();
// for(i=0;i<=n;i++)
// {
// while(!((c>='0'&&c<='9')||c=='-')) c=getchar();
// if(c=='-')
// fl=1,c=getchar();
// else
// fl=0;
// for(j=0;j<pnum;j++)
// {
// for(i1=fl;c>='0'&&c<='9';i1++)
// {
// a[j][i]=(a[j][i]*10+c-'0');
// while(a[j][i]>=prime[j]) a[j][i]-=prime[j];
// //ans[j][i]-=prime[j]
// c=getchar();
// }
// if(fl) a[j][i]=prime[j]-a[j][i];
// }
// }
for(i=0;i<=n;i++)
{
scanf("%s",s);
if(s[0]=='-')
fl=1;
else
fl=0;
sl=strlen(s);
for(j=0;j<pnum;j++)
{
for(i1=fl;i1<sl;i1++)
a[j][i]=(a[j][i]*10+s[i1]-'0')%prime[j];
if(fl) a[j][i]=prime[j]-a[j][i];
}
}
for(p=0;p<pnum;p++)
{
for(j=1;j<=m;j++)
if(!nok[j])
{
for(i=n;i>=1;i--)
ans[p][j]=(ans[p][j]+a[p][i])*j%prime[p];
ans[p][j]+=a[p][0];
while(ans[p][j]>=prime[p]) ans[p][j]-=prime[p];
if(ans[p][j]!=0)
for(k=j;k<=m;k+=prime[p])
nok[k]=1;
}
}
for(i=1;i<=m;i++)
if(!nok[i])
aa++;
printf("%lld\n",aa);
for(i=1;i<=m;i++)
if(!nok[i])
printf("%lld\n",i);
return 0;
}
洛谷 P2312 解方程的更多相关文章
- 洛谷P2312 解方程题解
洛谷P2312 解方程题解 题目描述 已知多项式方程: \[a_0+a_1x+a_2x^2+\cdots+a_nx^n=0\] 求这个方程在 \([1,m]\) 内的整数解(\(n\) 和 \(m\) ...
- 洛谷 P2312 解方程 解题报告
P2312 解方程 题目描述 已知多项式方程: \(a_0+a_1x+a_2x^2+\cdots+a_nx^n=0\)求这个方程在 \([1,m]\) 内的整数解(\(n\) 和 \(m\) 均为正整 ...
- 洛谷 P2312 解方程 题解
P2312 解方程 题目描述 已知多项式方程: \[a_0+a_1x+a_2x^2+\cdots+a_nx^n=0\] 求这个方程在 [1,m][1,m] 内的整数解(\(n\) 和 \(m\) 均为 ...
- [NOIP2014] 提高组 洛谷P2312 解方程
题目描述 已知多项式方程: a0+a1x+a2x^2+..+anx^n=0 求这个方程在[1, m ] 内的整数解(n 和m 均为正整数) 输入输出格式 输入格式: 输入文件名为equation .i ...
- 2018.11.02 洛谷P2312 解方程(数论)
传送门 直接做肯定会TLETLETLE. 于是考验乱搞能力的时候到了. 我们随便选几个质数来checkcheckcheck合法解,如果一个数无论怎么checkcheckcheck都是合法的那么就有很大 ...
- 洛谷P2312 解方程 [noip2014] 数论
正解:数论 解题报告: 这儿是,传送门qwq 又是很妙的一道题呢,专门用来对付我这种思维僵化了的傻逼的QAQ 首先看题目的数据范围,发现a<=1010000,很大的一个数据范围了呢,那这题肯定不 ...
- 洛谷P2312解方程
传送门 思路分析 怎么求解呢? 其实我们可以把左边的式子当成一个算式来计算,从1到 $ m $ 枚举,只要结果是0,那么当前枚举到的值就是这个等式的解了.可以通过编写一个 $ bool $ 函数来判断 ...
- 洛谷P2312解方程题解
题目 暴力能得\(30\),正解需要其他的算法操作,算法操作就是用秦九韶算法来优化. 秦九韶算法就是求多项式的值时,首先计算最内层括号内一次多项式的值,然后由内向外逐层计算一次多项式的值,然后就将求\ ...
- 洛谷P2312 解方程(暴力)
题意 题目链接 Sol 出这种题会被婊死的吧... 首先不难想到暴力判断,然后发现连读入都是个问题. 对于\(a[i]\)取模之后再判断就行了.注意判断可能会出现误差,可以多找几个模数 #includ ...
随机推荐
- JVM原理及内存溢出
JVM原理及内存溢出
- Android c/c++ 应用向linux 平台迁移执行
鉴于近期在minicamera (linux + FPGA) 平台上模拟 安卓系统camera流程遭遇不断升级同步的困扰.尤其是 不开放源代码后 , 应用要链接封闭动态库造成的困难.以及在sprdis ...
- 【LeetCode-面试算法经典-Java实现】【066-Plus One(加一)】
[066-Plus One(加一)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given a non-negative number represented as ...
- Android开发:怎样隐藏自己的app应用
本文主要介绍怎样通过改动AndroidManifest.xml清单文件来达到隐藏自身应用的目的,不是隐藏第三方应用.为了不浪费大家时间.特此说明. 转载请注明作者xiong_it和链接:http:// ...
- centos 安装tkdiff
http://sourceforge.net/projects/tkdiff/files/tkdiff/4.2/ 下载tkdiff-4.2.tar.gz 然后在centos下解压 将tkdiff c ...
- 在VC6.0中多线程编程演示样例(带同步信号量)
直接上代码: #include <windows.h>//必要的头文件,使用Windows API函数 #include <stdio.h> int index = 0; in ...
- ubuntu安装jdk 1.6
linux下安装JDK1.6 1. 去http://java.sun.com/j2se/1.4.2/download.html 下载一个Linux Platform的JDK,建议下载RPM自解压格式的 ...
- linux input子系统 — TP A/B(Slot)协议【转】
本文转载自:http://blog.csdn.net/u012719256/article/details/53609906 将A/B协议这部分单独拿出来说一方面是因为这部分内容是比较容易忽视的,周围 ...
- HDU3394 Railway —— 点双联通分量 + 桥(割边)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3394 Railway Time Limit: 2000/1000 MS (Java/Others) ...
- oracle 建表 主键自增序列/////
oracle 建表 主键自增序列 (2011-10-12 11:59:22) 转载▼ 标签: 杂谈 分类: oracle SQL> create table sms_activity( 2 ...