NOIP 2014 Senior 6
来源:互联网 发布:知乎查看自己的匿名 编辑:程序博客网 时间:2024/06/07 01:42
思路 1
肯定一开始就能想到高精度吧。不过这个数据规模看上去有点非常大,而且需要写的有比较、负数、加法、乘法、乘方、高精度输入。。。反正比赛时我是不愿意相信会单独考这么一个高精度的。
听说能拿50分。
思路 2
加法和乘法以及乘方?嗯,以前遇到过的,这样的操作是符合模运算规则的。所以我们可以使用模运算,枚举除数,进行多次判断,如果都满足算出来等于0,那我们就可以说这个x代进去算出来应该是0,如果有任何一个都不满足,那我们说这个x代进去算肯定不是0。
所以选哪些作为除数呢?又要选多少呢?毫无疑问,这个除数必须是个质数。在一开始,我选择了10个较大质数,结果过了7个点:最后3个点因为m太大超时了。
这个思路还是有一些东西值得学(复)习的,比如:
(1)输入大整数
根据读入优化的思路写一波
bool readIn(char* str, int* l) //重载,返回是否为负数。我们保证str为空串。{ bool minus = false; int& length = *l; length = 0; int ch = getchar(); while (!(ch == '-' || ch >= '0' && ch <= '9')) ch = getchar(); if (ch == '-') { minus = true; ch = getchar(); } while (ch >= '0' && ch <= '9') { str[length++] = ch - '0'; //就不保存字符了 ch = getchar(); } return minus;}
(2)大整数求余
一个函数就解决,不要想到去写高精度除法= =。
INT Mod(int index, INT mod){ INT ret = 0; for (int i = 0; i < length[index]; i++) { ret *= digit; ret += origin[index][i]; //刚刚输入的字符串 ret %= mod; } if (minus[index]) { ret = -ret; ret += mod; //模运算法则 } return ret % mod;}
(3)秦九韶算法
终于把它从数学书上搬过来了。。。
//for (int i = 0; i < size; i++) //预处理系数,将系数分别与那几个质数求余//{ //size为质数个数// for(int j = 0; j <= n; j++)// {// A[i][j] = Mod(j, Prime[i]);// }//}INT Polynomial(INT x, int modIndex){ INT ret = A[modIndex][n]; for (int i = n; i >= 1; i--) { ret *= x; ret %= Prime[modIndex]; ret += A[modIndex][i - 1]; ret %= Prime[modIndex]; } return ret;}
记不到?模拟几遍就写出来了,不多说。
主程序
std::vector<int> ans; for (int x = 1; x <= m; x++) { bool bOk = true; for (int i = 0; i < size; i++) { if (Polynomial(x, i) != 0) { bOk = false; break; } } if (bOk) { ans.push_back(x); } } printf("%d\n", ans.size()); for (int i = 0; i < ans.size(); i++) { printf("%d\n", ans[i]); }
可以发现,即使在判断时有个break,它也不会起太大的作用,因为它最多只能加速一个数,这也是这个算法只能得70分的原因。
思路 3
如果我们确定了一个数可能是解,是否可以推算出其它数也可能是解呢?答案是肯定的。把多项式的和用秦九韶算法的形式写出来,发现当x加p后余上p的值不变,即若
所以使用筛法时,应使用一个较小的(但不能太小)的质数,最后检查时,应使用较大的质数。具体要用多少个来检查呢?建议考试时多用几个来检查,保险一点。实测只需要用一个来筛,一个来检查就够了。
参考代码
#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <string>#include <stack>#include <queue>#include <deque>#include <map>#include <set>using std::cin;using std::cout;using std::endl;typedef long long INT;int readIn(){ bool minus = false; int a = 0; int ch = getchar(); while (!(ch == '-' || ch >= '0' && ch <= '9')) ch = getchar(); if (ch == '-') { minus = true; ch = getchar(); } while (ch >= '0' && ch <= '9') { a *= 10; a += ch; a -= '0'; ch = getchar(); } if(minus) a = -a; return a;}bool readIn(char* str, int* l){ bool minus = false; int& length = *l; length = 0; int ch = getchar(); while (!(ch == '-' || ch >= '0' && ch <= '9')) ch = getchar(); if (ch == '-') { minus = true; ch = getchar(); } while (ch >= '0' && ch <= '9') { str[length++] = ch - '0'; ch = getchar(); } return minus;}const int maxn = 105;int n, m;bool minus[maxn];int length[maxn];const INT digit = 10;char origin[maxn][10005];const INT Prime[] ={ 10007, //用于快速求值 199999769 //用于准确判断};const int size = sizeof(Prime) / sizeof(INT);INT A[size][maxn];INT Mod(int index, INT mod){ INT ret = 0; for (int i = 0; i < length[index]; i++) { ret *= digit; ret += origin[index][i]; ret %= mod; } if (minus[index]) { ret = -ret; ret += mod; } return ret % mod;}INT Polynomial(INT x, int modIndex){ INT ret = A[modIndex][n]; for (int i = n; i >= 1; i--) { ret *= x; ret %= Prime[modIndex]; ret += A[modIndex][i - 1]; ret %= Prime[modIndex]; } return ret;}void run(){ n = readIn(); m = readIn(); for (int i = 0; i <= n; i++) { minus[i] = readIn(origin[i], &length[i]); } for (int i = 0; i < size; i++) { for(int j = 0; j <= n; j++) { A[i][j] = Mod(j, Prime[i]); } } std::vector<bool> isAns(m + 1); std::vector<int> ans; for (int x = 1; x < Prime[0]; x++) { if (!Polynomial(x, 0)) { for(int i = x; i <= m; i += Prime[0]) { isAns[i] = true; } } } for (int x = 1; x <= m; x++) { if(isAns[x] && !Polynomial(x, 1)) { ans.push_back(x); } } printf("%d\n", ans.size()); for (int i = 0; i < ans.size(); i++) { printf("%d\n", ans[i]); }}int main(){ run(); return 0;}
怎么得到素数呢?可以自己另写程序使用埃式筛法求得。所以,这道题还是算是有点数论的味道(勿喷)。
bool isntPrime[200000000];int from = readIn();int n = readIn();int to = sqrt(n);for(int i = 2; i <= to; i++){ if(!isntPrime[i]) { for(int j = i * i; j <= n; j += i) { isntPrime[j] = true; } }}
- NOIP 2014 Senior 6
- NOIP 2014 Senior 2
- NOIP 2014 Senior 3
- NOIP 2014 Senior 5
- NOIP 2011 Senior 6
- NOIP 2016 Senior 6
- NOIP 2015 Senior 6
- NOIP 2013 Senior 6
- NOIP 2017 Senior 6
- NOIP 2009 Senior 1
- NOIP 2009 Senior 4
- NOIP 2009 Senior 3
- NOIP 2011 Senior 2
- NOIP 2011 Senior 3
- NOIP 2011 Senior 4
- NOIP 2011 Senior 5
- NOIP 2012 Senior 2
- NOIP 2012 Senior 5
- centos 7 opencv3 安装——yyw合并
- MSM LK启动流程初探
- Python3《机器学习实战》学习笔记(一):k-近邻算法(史诗级干货长文)
- viewpager+fragment的懒加载。必须要掌握
- 深度神经网络(DNN)反向传播算法(BP)
- NOIP 2014 Senior 6
- ActiveMQ消息特性:通知消息(Advisory Message)
- 学习oracle数据库写在前面的话
- Crazy Learning for Day 15
- ARP协议详解
- 标准作息表
- 【贪心】Stripies POJ 1862
- 【HNOI2016模拟4.14】A
- Linux--dd命令