1.计数问题

算法分析

剥数。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
int main() // 剥数
{int n, x;scanf("%d%d", &n, &x);int sum = 0;for (int i = 1; i <= n; ++i){int t = i;while (t){if (t % 10 == x) ++sum;t /= 10;} }printf("%d\n", sum);return 0;
}

2.表达式求值

算法分析

有一个取巧的读入方式。仔细观察数据特点,第一个数据是数字,第二个是运算符,第三个也是数字,后面就是运算符和数字成对出现了。可以用while+scanfwhile + scanfwhile+scanf读入不定个数的数据。读入的时候,遇到数字就入栈,遇到乘号就从栈顶弹出一个数和此时读入的数相乘,然后结果再入栈。因为只有加号和乘号,最后栈里的数据都是要相加的,加起来就是答案。每一步都要模10000。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#define ll long long int
using namespace std;
const int P = 10000;
stack<ll> s;
int main()
{ char c;ll a;scanf("%lld", &a);s.push(a % P);while (scanf("%c%lld", &c, &a) == 2) // 读入不定个数  {if (c == '*'){ll u = s.top(); s.pop();s.push(a % P * u % P);}else s.push(a % P);}ll ans = 0;while (s.size()){ans += s.top();ans %= P;s.pop();}printf("%lld\n", ans % P);return 0;
}

算法拓展

1.递归求中缀表达式。对于区间[l,r][l, r][l,r],每次从右侧找第一个加号,左右两侧的结果加起来。如果没有加号,找右数第一个乘号,结果乘起来。如果加号和乘号都没有,说明这是一个数字,直接返回。

利用前缀和,迅速判断区间内是否有加号或乘号。有一个注意事项:加号和乘号最多有10万个,每个符号配一个数字,数字的字符个数未知,不好开数组。开小了会RE。开1000万能过。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#define ll long long
using namespace std;
const int P = 10000;
char s[10000010];
int sumjia[10000010], sumcheng[10000010];
int dfs(int l, int r)
{if (sumjia[r] - sumjia[l-1] == 0 && sumcheng[r] - sumcheng[l-1] == 0){int x = 0;for (int i = l; i <= r; ++i) x = x * 10 + s[i] - '0';return x % P;}if (sumjia[r] - sumjia[l-1] == 0) {int i;for (i = r; i >= l; --i) if (s[i] == '*') break;return dfs(l, i-1) % P * dfs(i+1, r) % P;}else{int i;for (i = r; i >= l; --i) if (s[i] == '+') break;return (dfs(l, i-1) % P + dfs(i+1, r) % P) % P;}
}
int main()
{scanf("%s", s + 1);int n = strlen(s+1);for (int i = 1; i <= n; ++i){if (s[i] == '+') sumjia[i] = sumjia[i-1] + 1;else sumjia[i] = sumjia[i-1];if (s[i] == '*') sumcheng[i] = sumcheng[i-1] + 1;else sumcheng[i] = sumcheng[i-1];}printf("%d\n", dfs(1, n));return 0;
}

2.中缀表达式转后缀再计算。能做,不过没有上述两个方法简单。

3.小朋友的数字

算法分析

这里面涉及到两个概念:特征值和分数。先求特征值,就是区间和。分两种情况,对于第iii个小朋友,他的特征值可以包含自身iii和不包含自身。包含iii的情况,就是之前解决过的最大子段和问题。不包含的话,直接使用上一个小朋友的数据即可。

t[i]t[i]t[i]:包含iii的最大字段和。
f[i]f[i]f[i]:iii的特征值。

ll minsum = 0;
t[1] = sum[1];
minsum = min(minsum, t[1]);
for (int i = 2; i <= n; ++i)
{t[i] = sum[i] - minsum;minsum = min(minsum, sum[i]);
}
f[1] = t[1];
for (int i = 2; i <= n; ++i)f[i] = max(t[i], f[i-1]);

再求分数。方法类似。

s[i]s[i]s[i]:iii小朋友的分数。

最后输出的时候,不管正数还是负数,直接模P输出即可,不用做特殊处理。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
int n, p, a[1000010];
ll sum[1000010], t[1000010]; // t[i]:[j, i]最大值,含i
ll f[1000010]; // 特征值
ll s[1000010]; // 分数
int main()
{scanf("%d%d", &n, &p);for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);for (int i = 1; i <= n; ++i) sum[i] = sum[i-1] + a[i];ll minsum = 0;t[1] = sum[1];minsum = min(minsum, t[1]);for (int i = 2; i <= n; ++i) {t[i] = sum[i] - minsum;minsum = min(minsum, sum[i]);}f[1] = t[1];for (int i = 2; i <= n; ++i)f[i] = max(t[i], f[i-1]);// ss[1] = f[1];ll maxval = s[1] + f[1];for (int i = 2; i <= n; ++i){s[i] = maxval;maxval = max(maxval, s[i] + f[i]);}maxval = -1e9;for (int i = 1; i <= n; ++i) maxval = max(maxval, s[i]);printf("%lld\n", maxval % p);return 0;
}

以上代码80分。原因是分数爆longlonglong \, longlonglong。特征值会在longlonglong \, longlonglong范围内,最大是101510^{15}1015,分数的本质就是特征值的累加,最大可能会到102110^{21}1021。那么,能否在上述过程中,边求分数边模P呢?不可以。连续模P得是在线性运算下,求最大值不是线性运算,不能模P。考虑用其他方法计算分数。

对于第iii个小朋友来说,s[i−1]s[i-1]s[i−1]存的是[1,i−2][1, i -2][1,i−2]个小朋友特征值加分数的最大值,还需要和第i−1i-1i−1个小朋友的分数加特征值进行比较。如果f[i−1]<0f[i-1]< 0f[i−1]<0,则取s[i]=s[i−1]s[i] = s[i-1]s[i]=s[i−1],否则取s[i]=s[i−1]+f[i−1]s[i] = s[i-1] + f[i-1]s[i]=s[i−1]+f[i−1]。因为这是线性运算,可以模P。

s[1] = f[1];
s[2] = s[1] + f[1];
for (int i = 3; i <= n; ++i)
{if (f[i-1] < 0) s[i] = s[i-1];else s[i] = s[i-1] + f[i-1];           s[i] %= p;
}

最后的结果不能是从前到后扫描取最大值,因为是模P下的。如果最后s[n]>0s[n]>0s[n]>0,结果就是s[n]s[n]s[n],否则结果就是s[1]s[1]s[1]。这题目坑还是很多的。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
int n, p, a[1000010];
ll sum[1000010], t[1000010]; // t[i]:[j, i]最大值,含i
ll f[1000010]; // 特征值
ll s[1000010]; // 分数   s[i]会爆long long
int main()
{scanf("%d%d", &n, &p);for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);for (int i = 1; i <= n; ++i) sum[i] = sum[i-1] + a[i];ll minsum = 0;t[1] = sum[1];minsum = min(minsum, t[1]);for (int i = 2; i <= n; ++i) {t[i] = sum[i] - minsum;minsum = min(minsum, sum[i]);}f[1] = t[1];for (int i = 2; i <= n; ++i)f[i] = max(t[i], f[i-1]);// ss[1] = f[1];s[2] = s[1] + f[1];for (int i = 3; i <= n; ++i){if (f[i-1] < 0) s[i] = s[i-1];else s[i] = s[i-1] + f[i-1];         s[i] %= p;}ll maxval = s[1];if (s[n] > 0) maxval = s[n];printf("%lld\n", maxval % p);return 0;
}

4.车站分级

算法分析

从题意中可以看出:如果火车经过一个车站停了,那么下一个等级低的车站可停可不停,但是等级大于或等于他的一定停。所以从给出的停靠的车站推不出什么关系,但是起始站到终点站之间凡是没有停靠的车站,其等级一定低于停靠的车站。这样可以从等级低的向等级高的车站连边,转图论。求最长路。

可以用最长路算法求。因为本题中边权可理解为1,所以也可以用拓扑排序的思想。一层层的扫描,扫完一层,答案加1。最后也是最长路。图中不会出现环,有环的话,说明矛盾了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#define ll long long
using namespace std;
struct node
{int next, to;
}edg[1000010];
int h[1010], cnt;
int n, m, vis[1010], sedge[1010][1010], sdu[1010];
vector<int> q, q1;
queue<int> s, s1;
void sadd(int u, int v)
{++cnt;edg[cnt].next = h[u];edg[cnt].to = v;h[u] = cnt;
}
int main()
{scanf("%d%d", &n, &m);int t, c;for (int i = 1; i <= m; ++i){scanf("%d", &t);for (int j = 0; j < q.size(); ++j) vis[q[j]] = 0;q.clear();q1.clear();int st, ed; // 始发站  终点站  scanf("%d", &c); ++vis[c];q.push_back(c); st = c;for (int j = 2; j < t; ++j){scanf("%d", &c); ++vis[c];q.push_back(c);  // 停靠站  }scanf("%d", &c); ++vis[c];q.push_back(c); ed = c;for (int j = st; j <= ed; ++j)if (!vis[j]) q1.push_back(j); // 非停靠站  for (int j = 0; j < q.size(); ++j){int v = q[j];for (int k = 0; k < q1.size(); ++k){int u = q1[k];if (!sedge[u][v]){sadd(u, v);++sdu[v];sedge[u][v] = 1;}}}}// 拓扑 队列  int ans = 0;for (int i = 1; i <= n; ++i) if (!sdu[i]) s.push(i);while (s.size()){++ans;while (s.size()){int u = s.front(); s.pop();for (int i = h[u]; i; i = edg[i].next){--sdu[edg[i].to];if (!sdu[edg[i].to]) s1.push(edg[i].to);}}while (s1.size()){s.push(s1.front()); s1.pop();}}  printf("%d\n", ans);return 0;
}

NOIP2013普及组复赛 解题分析相关推荐

  1. NOIP2011普及组复赛 解题分析

    1.数字反转 算法分析 反转后需要考虑前导0.重新组数就可以规避这个问题.就是剥数和组数的过程. #include <iostream> #include <cstdio> # ...

  2. NOIP2015普及组复赛 解题分析

    1.金币 算法分析 直接模拟. #include <iostream> #include <cstdio> #include <cstring> using nam ...

  3. NOIP2013 提高组复赛解题报告

    NOIP2013 提高组复赛 day1 day\;1 1002. 火柴排队 贪心+数据结构/归并排序 这个"相邻交换"让我联想到了NOIP2012_day1_task2_game那 ...

  4. C语言普及组NOIP考试培训,NOIP 2018普及组复赛解题报告来了!

    以下解题思路及选手代码未经官方评测,仅供参考,复赛成绩以官方(CCF)评测结果为准. 主要考察字符串.参考代码: #include int main() { int ans = 0; char ch; ...

  5. NOIP2013普及组复赛试题_计数问题

    http://ybt.ssoier.cn:8088/problem_show.php?pid=1961 #include<iostream> using namespace std; in ...

  6. java 车站分级问题_【NOIP2013 普及组】车站分级

    [NOIP2013 普及组]车站分级 一.题目 [NOIP2013 普及组]车站分级 时间限制: 1 Sec  内存限制: 128 MB 提交: 3  解决: 0 [提交][状态][讨论版] 题目描述 ...

  7. 信息学奥赛一本通 1961:【13NOIP普及组】计数问题 | 洛谷 P1980 [NOIP2013 普及组] 计数问题

    [题目链接] ybt 1961:[13NOIP普及组]计数问题 洛谷 P1980 [NOIP2013 普及组] 计数问题 [题目考点] 1. 数字拆分 [解题思路] 遍历1~n的各个数字,对每个数字做 ...

  8. 信息学奥赛一本通 1962:【13NOIP普及组】表达式求值 | 洛谷 P1981 [NOIP2013 普及组] 表达式求值

    [题目链接] ybt 1962:[13NOIP普及组]表达式求值 洛谷 P1981 [NOIP2013 普及组] 表达式求值 [题目考点] 栈 中缀表达式转后缀表达式,后缀表达式求值 中缀表达式求值 ...

  9. 近年NOIP普及组复赛题目的简单讲解

    NOIP2015普及组复赛 整套题都出得不错,难度适中,层次分明 建议同学们在做题的时候还是先在草稿纸上分析,把关键算法的伪代码写出来,然后设计数据进行静态查错,没有问题后再到电脑上敲出代码.实际效率 ...

  10. P1983 [NOIP2013 普及组] 车站分级——拓扑排序+dp

    [NOIP2013 普及组] 车站分级 题目描述 一条单向的铁路线上,依次有编号为 $1, 2, -, n $的 $n $个火车站.每个火车站都有一个级别,最低为 111 级.现有若干趟车次在这条线路 ...

最新文章

  1. LINQ获取两个List的交集
  2. java 程序运行过程 简介
  3. Django 数据库ORM 操作 - 字段的类型和参数
  4. Win10如何远程连接Windows Server 2008,以及提示“您的凭证不工作”问题解决
  5. Spring事务与自定义多线程陷阱
  6. xxx定律-poj-3782
  7. war包怎么解压_渣渣辉表情包下载-渣渣辉抖音表情包动态图下载
  8. 安卓开发 登录用户信息缓存_在Linux上使用finger命令查询登录用户信息
  9. php内存泄漏的后果,记一次php内存泄漏的排查经过
  10. 帆软日期格式转换_FineReport帆软报表相关学习笔记,纪要
  11. steam授权_验号机器人正式上线,支持检验csgo账号、steam账号信息
  12. linux 安装protoc
  13. Ubuntu 12.04 安装离线词典
  14. 电商运营流程图模板分享
  15. win10怎么隐藏桌面计算机,Win10隐藏秘技大公开
  16. 如何判断两条直线是否相交
  17. Go开发 之 设计模式
  18. RADIUS 服务器之 hostapd 配置说明
  19. 小凯机器人软件_微信小凯机器人_小凯机器人需要下载吗
  20. KEIL-MDK快速格式化代码的方法

热门文章

  1. Python安装包下载、环境配置与工具包安装教程(详细版)
  2. 一信通短信接口对接_短信验证码接口轻松对接事项
  3. 短信平台接口怎么选择?看这一篇就够了
  4. “仿QQ局域网聊天软件”项目-常用编程技巧总结
  5. Springboot+Vue实现物业管理系统
  6. oracle启动crs要多久,oracle 10g CRS不能启动解决过程(hp-ux)
  7. API接口文档范文-API接口文档示例
  8. 《企业IT架构转型之道》边读边想——内容主线
  9. shapefile(.shp)空间数据格式详细说明
  10. python中unicode编码表_python unicode 编码整理