【随便做做】Codeforces#86 Problem C Double Happiness
2015-09-07 22:18
267 查看
静态数组内存是受不了的。但同学好机智,用vectorvector强行开150000000150000000的数组,水了过去。。。
令f(x)f(x)表示范围[1,x][1,x]内满足题意的tt的个数,那么ans=f(r)−f(l−1)ans=f(r)-f(l-1)我们考虑打表求解,显然,不可以直接打表,所以我们考虑将33亿分段,每10000001000000分一段,于是总共需要预处理出300300个数,即f(0),f(1000000),f(2000000),…,f(300000000)f(0),f(1000000),f(2000000),\dots,f(300000000)这在本地是可以O(n)O(n)地得到的(EularEular筛法O(n)O(n)+枚举完全平方数O(n)O(n)),然后对一个询问f(x)f(x),只需要在线求解xx%1000000这一部分即可。
我们举例说明求解f(11111111)f(11111111)的方法,查上述规模为300300的表格,我们发现有f(11000000)f(11000000)可用,也就是已知[1,11000000][1,11000000]内满足题意的数的个数;接下来,只需要求解范围[11000001,11111111][11000001,11111111]内满足题意的个数即可,由于我们每10000001000000做一个分割,因此我们真正需要在线做的这部分规模不会大于10000001000000,就可以使用你喜欢的筛素数方法通过了。为了简洁,后面这部分窝就直接O(nn−−√)O(n\sqrt n)地做了。
本地离线预处理部分:
LinuxLinux下可在终端用下述命令将打表结果添加到
g++ c_gen.cpp -o c_gen –std=c++11
./c_gen >> c.cpp
WindowsWindows也类似,注意确认是否已手动将
g++ c_gen.cpp -o c_gen -std=c++11
c_gen >> c.cpp
注意二者的区别是运行生成的
扯远了。。。总之上述完成后,我们就得到想要的表了,当然,窝打的表是分段的,拿来用之前需要先处理出它的前缀和,即打的表统计的是[1,1000000],[1000001,2000000],…[1,1000000],[1000001,2000000],\dots各段的数量,我们真正需要的是比如[1,3000000][1,3000000]这样的形式,于是相当于需要前33项的和,又如[1,11000000][1,11000000]需要的是前1111项的和,随便一提,前缀和就是前若干项和。。。
然后就是下面的处理
值得一提的是,你也可以选择如每100000100000分为一段的方式,这样表格会长一些,将有300000000100000=3000{300000000\over100000}=3000项,或许应该稍微格式化一下,比如每打印1010项换一行,这样显得漂亮一些。。。
BTWBTW,上面有一个小优化,就是考虑i2+[ ]2=t,bound≤t≤ni^2+[\ \ ]^2=t,bound\le t\le n时,固定ii后,枚举第二项的大小,我们可以规定第二项≥i\ge i,进一步地,我们可以确定第二项的一个下限,即设第二项为jj,则至少有i2+j2≥boundi^2+j^2\ge bound,也就是j2≥bound−i2j^2\ge bound - i^2,或者说sq[j]≥bound−sq[i]sq[j]\ge bound - sq[i]。
令f(x)f(x)表示范围[1,x][1,x]内满足题意的tt的个数,那么ans=f(r)−f(l−1)ans=f(r)-f(l-1)我们考虑打表求解,显然,不可以直接打表,所以我们考虑将33亿分段,每10000001000000分一段,于是总共需要预处理出300300个数,即f(0),f(1000000),f(2000000),…,f(300000000)f(0),f(1000000),f(2000000),\dots,f(300000000)这在本地是可以O(n)O(n)地得到的(EularEular筛法O(n)O(n)+枚举完全平方数O(n)O(n)),然后对一个询问f(x)f(x),只需要在线求解xx%1000000这一部分即可。
我们举例说明求解f(11111111)f(11111111)的方法,查上述规模为300300的表格,我们发现有f(11000000)f(11000000)可用,也就是已知[1,11000000][1,11000000]内满足题意的数的个数;接下来,只需要求解范围[11000001,11111111][11000001,11111111]内满足题意的个数即可,由于我们每10000001000000做一个分割,因此我们真正需要在线做的这部分规模不会大于10000001000000,就可以使用你喜欢的筛素数方法通过了。为了简洁,后面这部分窝就直接O(nn−−√)O(n\sqrt n)地做了。
本地离线预处理部分:
/* ********************************************** File Name: c_gen.cpp Auther: zhengdongjian@tju.edu.cn Created Time: 2015年09月07日 星期一 21时35分46秒 *********************************************** */ #include <bits/stdc++.h> using namespace std; const int MAX = 300000001; const int MAX_SQ = 20001; bool is_prime[MAX]; bool yes[MAX]; int sq[MAX_SQ], sz = 0; int prime[MAX >> 4], pr = 0; int init() { memset(is_prime, true, sizeof(is_prime)); is_prime[0] = is_prime[1] = false; for (int i = 2; i < MAX; ++i) { if (is_prime[i]) { prime[pr++] = i; } for (int j = 0; j < pr && prime[j] <= MAX / i; ++j) { is_prime[prime[j] * i] = false; if (i % prime[j] == 0) break; } } for (int i = 1; i * i < MAX; ++i) { sq[sz++] = i * i; } return pr; } int main() { //printf("%d\n", init()); init(); memset(yes, false, sizeof(yes)); for (int i = 0; i < sz; ++i) { for (int j = i; j < sz; ++j) { int x = sq[i] + sq[j]; if (x >= MAX) break; if (is_prime[x]) { yes[x] = true; } } } int sum = 0; const int CUT = 1000000; for (int i = 1; i < MAX; ++i) { if (yes[i]) ++sum; if (i % CUT == 0) { printf("%d, ", sum); sum = 0; } } return 0; }
LinuxLinux下可在终端用下述命令将打表结果添加到
c.cpp后面,避免手动粘贴疏漏
g++ c_gen.cpp -o c_gen –std=c++11
./c_gen >> c.cpp
WindowsWindows也类似,注意确认是否已手动将
g++.exe添加进环境变量,否则
cmd下直接运行
g++是无法找到该程序的。具体请自行百度之。。。
g++ c_gen.cpp -o c_gen -std=c++11
c_gen >> c.cpp
注意二者的区别是运行生成的
c_gen的方式不同,LinuxLinux直接输入命令是只在
$PATH环境变量中包含的路径查找,并且不包含当前目录。试想,由于LinuxLinux下任何用户都有
/tmp的
rwx权限,一个普通用户在里面放置了一个恶意程序,甚至命名为
ls(
ls原本为系统程序,位于
/bin/ls,功能为列出当前目录下的文件/目录)!之后rootroot在
tmp中想查看文件,然后执行
ls。。。后果可想而知。。。也正因此,LinuxLinux执行当前目录下的程序需要输入
./程序名,相当于要强调“俺要运行当前目录下那个啥啥啥。。。”
扯远了。。。总之上述完成后,我们就得到想要的表了,当然,窝打的表是分段的,拿来用之前需要先处理出它的前缀和,即打的表统计的是[1,1000000],[1000001,2000000],…[1,1000000],[1000001,2000000],\dots各段的数量,我们真正需要的是比如[1,3000000][1,3000000]这样的形式,于是相当于需要前33项的和,又如[1,11000000][1,11000000]需要的是前1111项的和,随便一提,前缀和就是前若干项和。。。
然后就是下面的处理
/* ********************************************** File Name: c.cpp Auther: zhengdongjian@tju.edu.cn Created Time: 2015年09月07日 星期一 21时35分52秒 *********************************************** */ #include <bits/stdc++.h> using namespace std; const int MAX_N = 300000007; const int EVE = 1000000; const int MAX_SQ = 20001; const int MAX = 301; /* * tab[1]: 1 ~ EVE * tab[2]: EVE + 1 ~ 2EVE * .. * tab[MAX-1]: (MAX-2)*EVE + 1 ~ (MAX-1)*EVE */ int tab[MAX] = {0, 39176, 35241, 33867, 33219, 32691, 32139, 31928, 31499, 31341, 31080, 30899, 30913, 30576, 30405, 30301, 30139, 30087, 30002, 29854, 29814, 29600, 29719, 29406, 29422, 29436, 29274, 29336, 29150, 29172, 29094, 29091, 28875, 28873, 28902, 28653, 28729, 28749, 28687, 28754, 28595, 28584, 28417, 28392, 28489, 28355, 28315, 28386, 28313, 28256, 28258, 28169, 28080, 28070, 28052, 28033, 28035, 27971, 28017, 27892, 27899, 27976, 27713, 27847, 27868, 27831, 27821, 27783, 27794, 27716, 27699, 27611, 27660, 27723, 27534, 27588, 27680, 27510, 27458, 27448, 27443, 27498, 27578, 27454, 27448, 27327, 27347, 27304, 27472, 27326, 27266, 27219, 27227, 27345, 27189, 27308, 27228, 27199, 27167, 27086, 27143, 27101, 27097, 27178, 27021, 27107, 27013, 26975, 27086, 27143, 27133, 26917, 27074, 26976, 26792, 26905, 26928, 26827, 26892, 26881, 26925, 26796, 26823, 26879, 26934, 26831, 26788, 26788, 26857, 26912, 26781, 26706, 26816, 26714, 26709, 26784, 26590, 26671, 26605, 26625, 26836, 26539, 26668, 26606, 26717, 26639, 26632, 26642, 26559, 26499, 26563, 26417, 26555, 26338, 26617, 26477, 26456, 26642, 26415, 26339, 26483, 26470, 26399, 26468, 26593, 26352, 26354, 26345, 26398, 26378, 26469, 26346, 26372, 26390, 26434, 26306, 26359, 26331, 26390, 26348, 26469, 26168, 26342, 26128, 26258, 26390, 26251, 26268, 26241, 26223, 26395, 25941, 26110, 26293, 26226, 26247, 26183, 26099, 26034, 26139, 26190, 26168, 26268, 26107, 26223, 26137, 26001, 26145, 26052, 25999, 26168, 26038, 26225, 26168, 26057, 26095, 26173, 26094, 25948, 25966, 25999, 25994, 26045, 26114, 25971, 26158, 25913, 26090, 25813, 25930, 25903, 25956, 26020, 26001, 25825, 25939, 25950, 26045, 25925, 26008, 25808, 26013, 25938, 25712, 25883, 25989, 25900, 25794, 25760, 25943, 25783, 25953, 25667, 25756, 25915, 25963, 25824, 25858, 25833, 25905, 25729, 25951, 25770, 25971, 25767, 25859, 25928, 25627, 25767, 25863, 25623, 25772, 25706, 25657, 25806, 25819, 25724, 25712, 25735, 25587, 25726, 25606, 25780, 25597, 25743, 25704, 25615, 25592, 25770, 25735, 25588, 25755, 25680, 25519, 25692, 25737, 25552, 25616, 25639, 25521, 25530}; int sq[MAX_SQ]; //square bool is_prime[EVE + 1]; static int OFFSET; //[1, n] int gao(int n) { //printf("gao %d\n", n); int sum = tab[n / EVE]; int bound = n / EVE * EVE + 1; if (bound > n) return sum; //printf("sum = %d, bound = %d\n", sum, bound); /* to-go: [bound, n], |n-bound|<EVE */ memset(is_prime, true, sizeof(is_prime)); if (bound == 1) is_prime[0] = false; for (int i = 2; i <= n / i; ++i) { for (int j = max(i, (bound + i - 1) / i) * i; j <= n; j += i) { is_prime[j - bound] = false; } } for (int i = 1; i < MAX_SQ; ++i) { for (int j = max(i, (int)(lower_bound(sq, sq + MAX_SQ, bound - sq[i]) - sq)); j < MAX_SQ; ++j) { int x = sq[i] + sq[j]; if (x > n) break; if (is_prime[x - bound]) ++sum; } } return sum; } int main() { /* pre-fix */ for (int i = 1; i < MAX; ++i) { tab[i] += tab[i - 1]; } for (int i = 1; i < MAX_SQ; ++i) { sq[i] = i * i; } int le, ri; while (cin >> le >> ri) { cout << gao(ri) - gao(le - 1) << endl; } return 0; }
值得一提的是,你也可以选择如每100000100000分为一段的方式,这样表格会长一些,将有300000000100000=3000{300000000\over100000}=3000项,或许应该稍微格式化一下,比如每打印1010项换一行,这样显得漂亮一些。。。
BTWBTW,上面有一个小优化,就是考虑i2+[ ]2=t,bound≤t≤ni^2+[\ \ ]^2=t,bound\le t\le n时,固定ii后,枚举第二项的大小,我们可以规定第二项≥i\ge i,进一步地,我们可以确定第二项的一个下限,即设第二项为jj,则至少有i2+j2≥boundi^2+j^2\ge bound,也就是j2≥bound−i2j^2\ge bound - i^2,或者说sq[j]≥bound−sq[i]sq[j]\ge bound - sq[i]。
相关文章推荐
- iOS开发:MVC(模型-视图-控制器)详解
- android shape的使用
- Android中数据存储——SQLite数据库存储数据
- android 之 数据库操作
- Android 之File数据存储--File
- Android中数据存储
- iOS编程:学习篇(十二)
- UIAlertView 写在NSObject的类中没有回调
- Android学习0906<十一>(ViewPager,fragment碎片)
- Android 笔记 6
- android学习笔记(19)数据库sqlite进阶
- Android button按键点击无反应
- Android学习总结(一)
- 转: Jenkins+Gradle实现android开发持续集成、打包
- Android创建快捷方式
- Android Service详解之生命周期
- Swift 教程:快速入门
- android存储方式之文件存储
- android学习笔记(18)数据库sqlite初步
- SQLite Android数据库详解