今天回来打的第一场NOIP难度的试题,结果惨不忍睹。写一下每道题的做法,然后每道题犯的__弱智__错误

UPD:2018.9.15 突然这篇题解就变成很多大佬要看的了,因为之前是写给自己看的,所以写的很简略,这次修改一下第二道题的描述(第一题建议找其他AC的人看看,我的做法比较依赖STL,而且比较难读懂)

Moni

题意

每天 \(t\) 时刻将会有人取车或者放车,这个序列满足FIFO原则,每个人的时间代价是 \(delta(t)\)。

有 \(q\) 次询问,每次问你如果在初始时刻投放 \(cnt\) 个车,总的代价是多少?

题目分析

看到这道题的时候第一想法是brute force,然后去拿个 \(60 pts\)

\(60 pts\) 做法:直接模拟计算每次出队的时候人的代价,加起来就行了。\(O(n * q)\)

花了15分钟写了个暴力,然后我们发现这个做法的问题是有很多次的计算是用的是之前使用过的,那么我们能不能直接通过上一个 \(cnt\), 直接算出这一个 \(cnt\)呢?

\(100 pts\) 做法: 本来想写个离散化,但是考虑到代码的整洁性, 直接使用用了std::map; 将取走记为正,放回记为负(方便计算贡献)

然后套个树状数组进行维护单点修改和查询区间和,你每次去做 \(cnt\) 的时候,先二分寻找第一次取完的位置, 然后直接更新贡献。

代码

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int maxn = 2e5 + 10;
  5. ll blocks[maxn];
  6. int redis[maxn];
  7. struct Opt {
  8. int t, det, q, op;
  9. }opt[maxn];
  10. map<int,int> dis;
  11. int C[maxn];
  12. int n,q;
  13. void ADD(int x, int v) {for(;x<=n+10;x+=x&-x) C[x]+=v;}
  14. ll query(int x) {ll ans=0;for(;x;x-=x&-x) ans+=C[x];return ans;}
  15. void add(int x,int det){
  16. ADD(1, det); ADD(x + 1, -det);
  17. }
  18. int main(){
  19. //freopen("moni.in", "r", stdin);
  20. //freopen("moni.out", "w", stdout);
  21. scanf("%d%d", &n, &q);
  22. dis[0] = 1; // add void point
  23. for(int i = 1; i <= n; ++i){
  24. char buf[5];
  25. int a, b;
  26. scanf("%s%d%d", buf, &a, &b);
  27. opt[i].t = a;
  28. opt[i].det = b;
  29. if(buf[0] == '+') {
  30. opt[i].op = 1; opt[i].q = opt[i - 1].q - b;
  31. } else {
  32. opt[i].op = 0; opt[i].q = opt[i - 1].q + b;
  33. }
  34. if(opt[i].q > 0) dis[opt[i].q] = 0; // add this pos
  35. }
  36. int discnt = 0, dismax = 0;
  37. for (map<int,int>::iterator pr = dis.begin(); pr != dis.end(); ++ pr) {
  38. pr->second = ++discnt;
  39. redis[discnt] = pr->first;
  40. dismax = max(dismax, pr->first);
  41. }
  42. for(int i = 1; i < n; ++i){
  43. if(opt[i].q <= 0) continue;
  44. int nopos = dis[opt[i].q];
  45. add(nopos, opt[i + 1].t - opt[i].t);
  46. }
  47. for(int i = 1; i <= discnt; ++i){
  48. blocks[i] = blocks[i - 1] + query(i) * (redis[i] - redis[i - 1]);
  49. }
  50. ll blocksum = blocks[discnt];
  51. for(int i = 1; i <= q; ++i) {
  52. int cnt;
  53. scanf("%d", &cnt);
  54. if(cnt < opt[n].q) {puts("INFINITY"); continue;}
  55. if(cnt >= dismax) {puts("0"); continue;}
  56. map<int,int>::iterator it;
  57. it = dis.lower_bound(cnt);
  58. ll res = blocksum - blocks[it->second];
  59. res += 1LL * (it->first - cnt) * query(it->second);
  60. cout << res << endl;
  61. }
  62. return 0;
  63. }

shuxue

题意

这道题题意很明显,公式都给出来了。

题目分析

这道题有一个很朴素的做法, 对于区间内的每个数进行质因数分解,然后忽略掉那个给出的mod值, 答案就是 \((p_1 + 1) * (p_2 + 1) * \cdots\) (\(p_i\) 为质因数的幂次)

例如,如果给出的mod值是13,那么对于\(\forall x \in [L, R]\),将$x = 2^{p_1} \times 3^{p_2} \times \cdots $算出来,那么它不包含13的倍数的因子个数就是排除\(13^{p_k}\),然后做上面的式子。

于是我们就有一个brute force的做法,先把质数筛出来,直接\(O( f(\sqrt{n}))\) 进行质因数分解,\(f(x)\)表示\(x\)以内的质数个数,然后计算答案就可以。总复杂度 \(O( D * f(\sqrt{n}))\)

上面的做法是 \(\le 60 pts\)但是如果对于每一个区间内的数进行分解,那么就会很耗时。所以我们考虑一下优化的做法

我们考虑对于这个区间一个数多出的冗杂计算,如果我们能直接看出这个数的质因子,那我们就可以不用枚举\(2~ \sqrt{n}\)的所有质因子进行试除。可以证明,如果有这样的一个算法,每个数的质因数分解就会在\(ln(n)\)的时间解决。

于是我们枚举所有的质数\(q\),在这个区间内找到第一个能被这个数整除的数,那么下一个能被整除的数就是当前数\(+q\)

我们用\(a[i]\)表示这个位置还剩余的数是多少,显然,在初始状态时\(a[i] = i\),每次找到因子\(p\),我们就进行如下更新\(a[i] /= p\)

当\(a[i] = 1\)时,表示这个数已经分解完毕。至此,我们已经将整个算法降为\(O(n \times ln(n))\)

如果考虑到\(10\)MB的内存,我们不难想出这道题需要打表完成(因为线性筛需要12MB内存),当然,你也可以实时进行MillerRobin素数测试,并且运用几个素数的性质,但我选择打表。

那么,如果按上面的分析,用\(a[i]\)储存位于\(i\)的当前值显然是不现实的,因为这样我们需要将数组开到\(a[1e12+10]\),注意到我们只会用到\(D\)的长度,那么我们选择用下标\(0\)去对应\(l\), \(r-l+1\)对应\(r\),就可以了。(这就是一种简单的映射关系)

  1. #inlcude <bits/stdc++.h>
  2. using namespace std;
  3. #define pb push_back
  4. #define forn(i) for(int i=1;i<=(int)(n);++i)
  5. #define rep(i,s,t) for(int i=(int)(s);i<=(int)(t);++i)
  6. const int maxn = 1e6 + 10;
  7. typedef long long qword;
  8. const int primeList[] = {...}
  9. const int maxm = 1e5 + 10;
  10. qword sum[maxm];
  11. qword a[maxm];
  12. inline void Init(int q, qword L, qword R) {
  13. for (int i = 0; i <= R - L; ++ i) {
  14. a[i] = i + L;
  15. while (a[i] % q == 0) {a[i] /= q; if (a[i] == 0) break;}
  16. sum[i] = 1;
  17. }
  18. }
  19. inline void work(int q, qword L, qword R) {
  20. Init(q, L, R);
  21. for(int i = 1; i <= tot && primeList[i] <= R; ++ i) {
  22. if (primeList[i] == q) continue;
  23. qword fir = (L / primeList[i] + (L % primeList[i] ? 1 : 0)) * primeList[i];
  24. for (qword j = fir; j <= R; j += primeList[i]) {
  25. qword res = 0;
  26. while (a[j-L] % primeList[i] == 0) {if (a[j - L] == 0) break; res ++; a[j-L] /= primeList[i];}
  27. sum[j-L] = 1ll * sum[j-L] * (res+1);
  28. }
  29. }
  30. qword ans = 0;
  31. for(int i=0; i <= R-L; ++i) {
  32. if(a[i] != 1) sum[i] = 1ll * sum[i] * 2;
  33. ans += sum[i];
  34. }
  35. cout << ans << endl;
  36. }
  37. int main() {
  38. freopen("shuxue.in","r",stdin);
  39. freopen("shuxue.out","w",stdout);
  40. // Euler_prime();
  41. int t;
  42. qword L, R;
  43. cin >> t >> L >> R;
  44. int q;
  45. rep(i,1,t) {
  46. cin >> q;
  47. work(q,L,R);
  48. }
  49. }

Boyi

题目分析

(这道题已经搞出了想法,等待回去测评)

说实话我并没有想出应该怎么做,但是这个题意的意思就是,妹子要容易获胜一点。(单生狗万岁)

因为男的是后手,男的获胜的情况是男的有必胜策略,其他的都是N。 于是,我果断选择全输出“N”水一下,期望得分(\(20 pts\)) 结果过了7个点, 简直迷。

2017NOIP模拟赛-科普基地的更多相关文章

  1. 【计蒜客2017NOIP模拟赛1】

    D1T1 题面 题解:一开始以为傻题,旋转个坐标系就行了,结果光荣爆零~ 结果发现旋转坐标系后,由于多了一些虚点,锤子砸到虚点上了~gg [没有代码] D1T2 题面 题解:计算出每个边对答案的贡献即 ...

  2. 2017NOIP模拟赛三 A酱的体育课

    据说改编自$CodeM 美团点评编程大赛初赛A 轮$ 简单的水题...考试的时候没想到,xjb打了暴力. 显然,第$x$个人排在第$y$个位置的情况总数为$(n-1)!$,在这些情况中,第$x$人对答 ...

  3. NOIP2017提高组 模拟赛13(总结)

    NOIP2017提高组 模拟赛13(总结) 第一题 函数 [题目描述] [输入格式] 三个整数. 1≤t<10^9+7,2≤l≤r≤5*10^6 [输出格式] 一个整数. [输出样例] 2 2 ...

  4. NOIP2017提高组模拟赛 9 (总结)

    NOIP2017提高组模拟赛 9 (总结) 第一题 星星 天空中有N(1≤N≤400)颗星,每颗星有一个唯一的坐标(x,y),(1≤x,y ≤N).请计算可以覆盖至少K(1≤K≤N)颗星的矩形的最小面 ...

  5. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  6. NOI模拟赛 Day1

    [考完试不想说话系列] 他们都会做呢QAQ 我毛线也不会呢QAQ 悲伤ING 考试问题: 1.感觉不是很清醒,有点困╯﹏╰ 2.为啥总不按照计划来!!! 3.脑洞在哪里 4.把模拟赛当作真正的比赛,紧 ...

  7. NOIP第7场模拟赛题解

    NOIP模拟赛第7场题解: 题解见:http://www.cqoi.net:2012/JudgeOnline/problemset.php?page=13 题号为2221-2224. 1.car 边界 ...

  8. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  9. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

随机推荐

  1. 【BZOJ3262】陌上花开 cdq分治

    [BZOJ3262]陌上花开 Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义 ...

  2. iOS tableview上放textfield

    用UITableViewController就可以了,处理键盘弹出和消失的代码已经封装在UITableViewController里了.

  3. linux清理n天前的文件命令

    记得有一次面试时问题改问题.现特此记录 find ${DATADIR}/user*.log -type f -mtime +1 -exec rm {} \; DATADIR是自己定义变量 -mtime ...

  4. redis数据持久化(快照/日志):

    1.RDB快照的配置选项: save // 900内,有1条写入,则产生快照 save // 如果300秒内有1000次写入,则产生快照 save // 如果60秒内有10000次写入,则产生快照 ( ...

  5. Linux下安装和卸载jdk步骤详述

    安装jdk 1.下载jdk8 jdk下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-21331 ...

  6. ebay商品基本属性组合成数据表格式,可用上传到系统递交数据

    该刊登表设计是利用VB写的,当时因为两个系统的数据不能直接对接,又copy并且组合SKU,一个表格一个表格填写,比较麻烦,还好刊登系统可以允许用excel表格上传数据 所以就下好模板,学了VB语言,在 ...

  7. Android官方架构组件介绍之ViewModel

    ViewModel 像Activity,Fragment这类应用组件都有自己的生命周期并且是被Android的Framework所管理的.Framework可能会根据用户的一些操作和设备的状态对Act ...

  8. LightBGM之Dataset

    最近使用了LightBGM的Dataset,记录一下: 1.说明: classlightgbm.Dataset(data, label=None, reference=None, weight=Non ...

  9. Popular Cows---poj2186(缩点,强联通)

    题目链接:http://poj.org/problem?id=2186 求有多少个点满足其他n-1个点都能到达这个点,是单向图: 所以我们可以把图进行缩点,之后求出度为0的那个点内包含的点的个数就是求 ...

  10. logging.basicConfig参数简介

    通过logging.basicConfig函数对日志的输出格式及方式做相关配置 import logging logging.basicConfig(level=logging.DEBUG, form ...