前言

  感觉稍微有些滑稽吧,毕竟每次练的题都是提高组难度的,结果最后的主要任务是普及组抱一个一等奖回来。至于我的分数嘛。。还是在你看完题解后写在[后记]里面。废话不多说,开始题解。

  (其实这篇博客只有题解没有心得。)



  第一题可以说的内容不是很多吧。直接暴力,计算每种铅笔需要花费的金额。

  只不过计算的时候,需要注意如下问题

  • 如果不是整数倍,除完后要加1
  • 神奇的Linux系统,很多人的第三个点wa了,所以要养成良好的编写代码的习惯

Code

 #include<iostream>
#include<fstream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<stack>
#include<set>
#include<map>
#include<queue>
using namespace std;
typedef bool boolean;
#define smin(a, b) (a) = min((a), (b))
#define smax(a, b) (a) = max((a), (b))
template<typename T>
inline void readInteger(T& u){
char x;
int aFlag = ;
while(!isdigit((x = getchar())) && x != '-');
if(x == '-'){
aFlag = -;
x = getchar();
}
for(u = x - ''; isdigit((x = getchar())); u = u * + x - '');
ungetc(x, stdin);
u *= aFlag;
} int n;
int cost[], num[];
int result; inline void init(){
result = 0xfffffff;
readInteger(n);
for(int i = , b; i <= ; i++){
b = ;
readInteger(num[i]);
readInteger(cost[i]);
b = n / num[i];
if(n % num[i] != ) b += ;
smin(result, b * cost[i]);
}
printf("%d", result);
} int main(){
freopen("pencil.in", "r", stdin);
freopen("pencil.out", "w", stdout);
init();
return ;
}


  第二题,暴力也不会TLE,所以就从起始日期枚举到结束日期,中途把进位之类的事情做好,问题就不会很大。

  只不过仍然会存在一些问题

  • 进位应该从低位开始判断
  • 注意进位的边界

  如果不小心手抽了,有些日期跳过了,或者有些地方出了点问题,变成了死循环,也很麻烦。

Code

 #include<iostream>
#include<fstream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<stack>
#include<set>
#include<map>
#include<queue>
using namespace std;
typedef bool boolean;
#define smin(a, b) (a) = min((a), (b))
#define smax(a, b) (a) = max((a), (b))
template<typename T>
inline void readInteger(T& u){
char x;
int aFlag = ;
while(!isdigit((x = getchar())) && x != '-');
if(x == '-'){
aFlag = -;
x = getchar();
}
for(u = x - ''; isdigit((x = getchar())); u = u * + x - '');
ungetc(x, stdin);
u *= aFlag;
} typedef class MyDate{
public:
int year;
int month;
int days;
MyDate(){}
MyDate(int num){
days = num % , num /= ;
month = num % , num /= ;
year = num;
}
boolean isHuiWen(){
if((year / ) != (days % )) return false;
if(((year / ) % ) != ((days / ) % )) return false;
if(((year / ) % ) != (month % )) return false;
if((year % ) != ((month / ) % )) return false;
return true;
}
void next(){
days++;
if(month == && days == && (year % != && (year % == || year % == ))){
days = ;
month++;
}else if(month == && days == && (!(year % != && (year % == || year % == )))){
days = ;
month++;
}else if(days == && (month == || month == || month == || month == || month == || month == || month == )){
days = ;
month++;
}else if(days == && (month == || month == || month == || month == )){
days = ;
month++;
}
if(month == ){
month = ;
year++;
}
}
boolean operator !=(MyDate another){
return !(this->days == another.days && this->month == another.month && this->year == another.year);
}
}MyDate; MyDate start;
MyDate _end; inline void init(){
int a, b;
readInteger(a);
readInteger(b);
start = MyDate(a);
_end = MyDate(b);
} inline void solve(){
int result = ;
while(start != _end){
if(start.isHuiWen()) result++;
start.next();
}
if(_end.isHuiWen()) result++;
printf("%d", result);
} int main(){
freopen("date.in", "r", stdin);
freopen("date.out", "w", stdout);
init();
solve();
return ;
}

[小结]

  这道题的难度不是特别难,但是,有个很明显的问题代码不简洁,而且好像读入优化也没什必要。。

明明70几行可以打完的程序,我却偏偏打了100行。

  如果是C语言用户,可以手打一些函数来代替我写的成员函数



  第三题是暴力加优化。

  首先讲思路吧。从头到尾扫描。需要一些量比如说上一艘船,对于它来说,在24小时内最早的一艘的位置(数组中)(就记为last吧)。还有当前不同种类的游客。还需要统计每个国籍的游客的数量(在这艘船的24小时内)

处理一艘船的时候,解决如下几个任务

  1. 更新对于已经不在24小时内的船,从last开始while循环,减去它们对应的国籍的游客数,再判断它是否为0,如果是,那么就把当前不同国籍的数量减去1
  2. 读入该艘船上的游客,如果这个国籍的数量为0,则把当前不同国籍的数量数加1,接着把这个国籍的游客数加1
  3. 输出这个不同国籍的数量

关于还省内存的事再说一下

  1. 使用vector
  2. 用两个一维数组,一个记录每艘船记录的数据在另一个数组中结束的下标,另一个就记录每艘船的游客的国籍

  由于vector太慢(虽说对于这道题已经足够了),而且经常手抖导致崩掉,果断嫌弃,改用方法2(我也不是说vector一定不好,至少对于很多时候还是挺管用的,效率也没有我说的那么糟糕,只不过我不喜欢而已)

  当然现在我很喜欢用vector偷懒  ——2018.2.13

Code

 #include<iostream>
#include<fstream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<stack>
#include<set>
#include<map>
#include<queue>
#include<vector>
using namespace std;
typedef bool boolean;
#define smin(a, b) (a) = min((a), (b))
#define smax(a, b) (a) = max((a), (b))
template<typename T>
inline void readInteger(T& u){
char x;
int aFlag = ;
while(!isdigit((x = getchar())) && x != '-');
if(x == '-'){
aFlag = -;
x = getchar();
}
for(u = x - ''; isdigit((x = getchar())); u = u * + x - '');
ungetc(x, stdin);
u *= aFlag;
} #define DAYSEC 86400 int n;
int tbegin;
int *times;
int listofx[];
int counter[];
int defkinds;
int *endsindex; inline void init(){
readInteger(n);
endsindex = new int[(const int)(n + )];
times = new int[(const int)(n + )];
tbegin = ;
endsindex[] = ;
for(int i = , peo; i <= n; i++){
readInteger(times[i]);
while(times[tbegin] <= times[i] - DAYSEC){
for(int j = endsindex[tbegin - ] + ; j <= endsindex[tbegin]; j++){
counter[listofx[j]]--;
if(counter[listofx[j]] <= ) defkinds--;
}
tbegin++;
}
readInteger(peo);
endsindex[i] = endsindex[i - ] + peo;
for(int j = endsindex[i - ] + ; j <= endsindex[i]; j++){
readInteger(listofx[j]);
if(counter[listofx[j]] == ) defkinds++;
counter[listofx[j]]++;
}
printf("%d\n", defkinds);
}
} int main(){
freopen("port.in", "r", stdin);
freopen("port.out", "w", stdout);
init();
return ;
}


  首先呢,想一个正确但不高效的方法,枚举a,b,c,d然后判断是否存在,理论复杂度O(m4)。

  接着可以发现一个物体的魔法值为2,还有一个魔法值为2,它们的贡献(实在找不到词了),是一样的。所以可以直接枚举数值,并且统计了数量后,可以O(1)判断d是否存在,复杂度降为O(4n3m)

  看着4m有些不爽,决定把它优化掉。既然魔法值一样的物品贡献一样就没必要按照每件来记录作为A、B、C、D物品的次数,直接按照数值来记录,就没有必要去用第四重循环了。

  计算的方法是这样的作为a物品的次数,根据乘法原理,就要加上可作为b物品、c物品和d物品的个数的乘积。没怎么说清楚,但是举个例子就好懂,比如说有1,5,24,26,26。当1作为a物品时,可作为b物品的是5,有一个,可作为c物品的是24,有一个,可作为d物品的是26,有两个,所以应该增加1*1*2次。其他同理。

  为了对付极端数据(不过貌似没有),所以我拍了序,加了个lower_bound,然后并没有AC(滑稽)

 #include<iostream>
#include<fstream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<stack>
#include<set>
#include<map>
#include<queue>
#include<ctime>
using namespace std;
typedef bool boolean;
#define smin(a, b) (a) = min((a), (b))
#define smax(a, b) (a) = max((a), (b))
template<typename T>
inline void readInteger(T& u){
char x;
int aFlag = ;
while(!isdigit((x = getchar())) && x != '-');
if(x == '-'){
aFlag = -;
x = getchar();
}
for(u = x - ''; isdigit((x = getchar())); u = u * + x - '');
ungetc(x, stdin);
u *= aFlag;
} int n, m;
int counter[];
vector<int> poses[];
int *fora, *forb, *forc, *ford;
int *mlist;
int *blist; int mylower_bound(int* a, int from, int end, int val){
int l = from, r = end - ;
while(l <= r){
int mid = (l + r) >> ;
if(val <= a[mid]) r = mid - ;
else l = mid + ;
}
return r + ;
} inline void init(){
readInteger(n);
readInteger(m);
fora = new int[(const int)(n + )];
forb = new int[(const int)(n + )];
forc = new int[(const int)(n + )];
ford = new int[(const int)(n + )];
mlist = new int[(const int)(m + )];
blist = new int[(const int)(m + )];
memset(fora, , sizeof(int) * (n + ));
memset(forb, , sizeof(int) * (n + ));
memset(forc, , sizeof(int) * (n + ));
memset(ford, , sizeof(int) * (n + ));
for(int i = , a; i <= m; i++){
readInteger(a);
counter[a]++;
poses[a].push_back(i);
mlist[i] = blist[i] = a;
}
} inline void solve(){
sort(mlist + , mlist + m + );
for(int i = ; i < n; i++){
if(!counter[i]) continue;
for(int j = i + ; j <= n; j += ){
if(!counter[j]) continue;
int k_start = mylower_bound(mlist, , m + , j + (j - i) * + );
if(k_start == m + ) continue;
for(int k = mlist[k_start]; k <= n; k++){
if(!counter[k]) continue;
int end = k + (j - i) / ;
if(end > n) break;
if(counter[end]){
fora[i] += counter[j] * counter[k] * counter[end];
forb[j] += counter[i] * counter[k] * counter[end];
forc[k] += counter[i] * counter[j] * counter[end];
ford[end] += counter[i] * counter[j] * counter[k];
}
}
}
}
for(int i = ; i <= m; i++){
printf("%d %d %d %d\n", fora[blist[i]], forb[blist[i]], forc[blist[i]], ford[blist[i]]);
}
} int main(){
freopen("magic.in", "r", stdin);
freopen("magic.out", "w", stdout);
init();
solve();
return ;
}

85分比赛时写的程序

  正解呢就是很神奇的方法来做的,首先看张图

  设c,d之间的差为i,则可以表示为上图。总长度大于9i。如果我们设这个长度是9i + 1,那么看,下图

  a2 - a1 = 1。那么c1,d1可以和a1,b1组合,说明c2,d2也可以和a1,b1组合,也就是说,在计算c,d的时候,只需要累加a,b搭配的方案数,再按照乘法原理就可以求出来了。枚举的量也大大减少了,只需要枚举i和d,a。时间复杂度成功地降为可以接受的范围。

Code(看了正解后写出来的程序)

 #include<iostream>
#include<fstream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<stack>
#include<set>
#include<map>
#include<queue>
#include<ctime>
using namespace std;
typedef bool boolean;
#define smin(a, b) (a) = min((a), (b))
#define smax(a, b) (a) = max((a), (b))
template<typename T>
inline void readInteger(T& u){
char x;
int aFlag = ;
while(!isdigit((x = getchar())) && x != '-');
if(x == '-'){
aFlag = -;
x = getchar();
}
for(u = x - ''; isdigit((x = getchar())); u = u * + x - '');
ungetc(x, stdin);
u *= aFlag;
} int n, m;
int counter[];
int *fora, *forb, *forc, *ford;
int *mlist;
int *blist; int mylower_bound(int* a, int from, int end, int val){
int l = from, r = end - ;
while(l <= r){
int mid = (l + r) >> ;
if(val <= a[mid]) r = mid - ;
else l = mid + ;
}
return r + ;
} inline void init(){
readInteger(n);
readInteger(m);
fora = new int[(const int)(n + )];
forb = new int[(const int)(n + )];
forc = new int[(const int)(n + )];
ford = new int[(const int)(n + )];
mlist = new int[(const int)(m + )];
blist = new int[(const int)(m + )];
memset(fora, , sizeof(int) * (n + ));
memset(forb, , sizeof(int) * (n + ));
memset(forc, , sizeof(int) * (n + ));
memset(ford, , sizeof(int) * (n + ));
for(int i = , a; i <= m; i++){
readInteger(a);
counter[a]++;
mlist[i] = blist[i] = a;
}
} inline void solve(){
// sort(mlist + 1, mlist + m + 1);
for(int i = ; i * < n; i++){
int len = * i + ;
int s = ;
for(int d = len + ; d <= n; d++){
s += counter[d - len] * counter[d - len + i * ];
ford[d] += s * counter[d - i];
forc[d - i] += s * counter[d];
}
s = ;
for(int a = n - len; a >= ; a--){
s += counter[a + len] * counter[a + len - i];
fora[a] += s * counter[a + i * ];
forb[a + i * ] += s * counter[a];
}
}
for(int i = ; i <= m; i++){
printf("%d %d %d %d\n", fora[blist[i]], forb[blist[i]], forc[blist[i]], ford[blist[i]]);
}
} int main(){
freopen("magic.in", "r", stdin);
freopen("magic.out", "w", stdout);
init();
solve();
return ;
}

PS


后话

  从上面的描述中应该可以猜到我noip普及组的分数了吧。我也就不说了。

  怎么说呢。。这也算是一个里程碑吧!虽然oi的路还长。。但是小小地庆祝一下也是可以的。

这次考得比较好的原因主要是心态比较好吧。也感谢四川吧,分数线比起什么浙江300分好多了(真的没有别的意思),所以说压力没那么大,而且靠差了还有提高组

noip2016普及组题解和心得的更多相关文章

  1. [题解]noip2016普及组题解和心得

    [前言] 感觉稍微有些滑稽吧,毕竟每次练的题都是提高组难度的,结果最后的主要任务是普及组抱一个一等奖回来.至于我的分数嘛..还是在你看完题解后写在[后记]里面.废话不多说,开始题解. 第一题可以说的内 ...

  2. noip2016普及组 题解

    T1 大水题,不解释 上考场代码 #include <algorithm> #include <cstdio> using namespace std; int main() ...

  3. NOIP2016普及组解题报告

    概述 \(NOIP2016\)普及组的前三题都比较简单,第四题也有很多的暴力分,相信参加了的各位\(OIer\)在\(2016\)年都取得了很好的成绩. 那么,我将会分析\(NOIP2016\)普及组 ...

  4. NOIP2008普及组题解

    NOIP2008普及组题解 从我在其他站的博客直接搬过来的 posted @ 2016-04-16 01:11 然后我又搬回博客园了233333 posted @ 2016-06-05 19:19 T ...

  5. NOIP2016普及组复赛解题报告

    提高组萌新,DAY1DAY2加起来骗分不到300,写写普及组的题目聊以自慰. (附:洛谷题目链接 T1:https://www.luogu.org/problem/show?pid=1909 T2:h ...

  6. NOIP2002-2017普及组题解

    虽然普及组一般都是暴力省一,但是有一些题目还是挺难的qwq个人觉得能进TG的题目会在前面打上'*' NOIP2002(clear) #include<bits/stdc++.h> usin ...

  7. 【做题记录】[NOIP2016 普及组] 魔法阵

    P2119 魔法阵 2016年普及组T4 题意: 给定一系列元素 \(\{X_i\}\) ,求满足以下不等式的每一个元素作为 \(a,b,c,d\) 的出现次数 . \[\begin{cases}X_ ...

  8. NOIP2016普及组

    普及组.代码有空发. 第一题就是买铅笔.暴力模拟绝对可取. 第二题就是回文日期.从t1的年份到t2的年份枚举每一年.头尾要特判. 第三题就是海港.骗了40分. 第四题就是魔法阵.不太好优化. 完.

  9. NOIP2008普及组 题解 -SilverN

    T1 ISBN号码 题目描述 每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括9位数字.1位识别码和3位分隔符, 其规定格式如“x-xxx-xxxxx-x”,其中符号“-”就是分隔符( ...

随机推荐

  1. ubuntu环境下快速搭建开发环境

    接触ubuntu已经半年了,虽然游戏啊qq啊在linux下配置稍微麻烦一些,但是作为开发环境,ubuntu真的是好东西,无论是c啊还是php and etc 看到官网上文档开发环境建议wamp,如果是 ...

  2. CF573C Bear and Drawing 构造+树论

    正解:构造 解题报告: 传送门! 这题首先可以画下图找下规律,,,然后通过找规律可以发现,最终的方案一定是一条主干+一些枝条,而且这些枝条的分杈一定小于等于2 明确一下主干的定义,最左边的节点和最右边 ...

  3. 洛谷P3966 单词 [TJOI2013] AC自动机

    正解:AC自动机 解题报告: 传送门! 先来提供一个40pts错解QAQ 首先看到这题就会想到AC自动机板子题2鸭!然后就照着那题的套路打一下,随便改一点儿,简单来说就是每次经过一个节点都要++,然后 ...

  4. caffe学习记录

    结论: caffe网络的prototxt训练与测试的时候用的是不同的,训练的时候用的prototxt里面有test只是为了测试网络的训练程度,里面的测试集是验证集,并不是真正我们测试的时候用的网络定义 ...

  5. Centos 集群配置SSH免登陆脚本

    首先编写脚本生成集群服务器列表: hostsList.sh #!/bin/bash preIp="11.11.225." pwd="dyj2017" for i ...

  6. C# 序列化(Serialize)与反序列化(Deserialize)

    序列化是将对象的状态信息转换为可保持或传输的格式的过程(一堆字符),比如转化为二进制.xml.json等的过程. 反序列化就是将在序列化过程中所生成的二进制串.xml.json等转换成数据结构或者对象 ...

  7. Hadoop集群安装-CDH5(5台服务器集群)

    CDH5包下载:http://archive.cloudera.com/cdh5/ 架构设计: 主机规划: IP Host 部署模块 进程 192.168.254.151 Hadoop-NN-01 N ...

  8. ES6(简)

    一. let.const 和 var let和const只在当前块级作用域中有效const用来声明常量var是全局作用域有效的 constants.js 模块export const A = 1;ex ...

  9. Look for the Air Jordan 32 in full family sizing

    Following the release of the 'Rosso Corsa' colorway, Jordan Brand is now set to officially launch th ...

  10. Vue.Js添加自定义插件

    基于上篇我们讲了 在window下搭建Vue.Js开发环境 我们可以开发自己的vue.js插件发布到npm上,供大家下载使用. 1.首先打开cmd命令窗口,进入我们的工作目录下 执行 cd E:\vu ...