前言

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

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



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

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

  • 如果不是整数倍,除完后要加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. NOIP2008普及组题解

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

  4. NOIP2016普及组解题报告

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

  5. NOIP2002-2017普及组题解

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

  6. NOIP2008普及组 题解 -SilverN

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

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

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

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

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

  9. NOIP2016普及组

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

随机推荐

  1. socket模块的getaddrinfo方法详解

    getaddrinfo方法用于通过url解析dns import sys,socket def dns_resolver(url): result = socket.getaddrinfo(url, ...

  2. db2数据库安装注意几个问题

    1.安装数据库的时候,db2用户使用的是系统中的用户.创建完数据库你会发现你电脑多了一个用户(可以在控制面板中查看到) 2.安装完数据库需要创建数据库.打开命令行cmd(注意一定要用管理员身份打开,不 ...

  3. 《JavaScript高级程序设计》学习笔记(3)——变量、作用域和内存问题

    欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 本节内容对应<JavaScript高级程序设计>的第四章内容. 1.函数:通过函数可以封装 ...

  4. RabbitMQ消息机制单人分发

    static void Main(string[] args) { // More.SendMessage(); var factory = new ConnectionFactory(); fact ...

  5. mongoDB学习笔记:了解与安装

    初次使用mongoDB是在2013年,项目组为了新产品的研发,使用了mongoDB,作为项目组的一名测试员,也就跟着学起来了. 1.了解mongoDB Mongo DB ,是目前在IT行业非常流行的一 ...

  6. Hibernate单元测试工具junit

    相关注解 @Text :测试方法 @Before :初始化方法 @After : 释放资源

  7. JOST数据 日期转换

    开发中有时候需要从服务器端返回json格式的数据,在后台代码中如果有DateTime类型的数据使用系统自带的工具类序列化后将得到一个很长的数字表示日期数据,如下所示: 复制代码代码如下: //设置服务 ...

  8. MongoDB学习笔记(索引)

    一.索引基础:    MongoDB的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的优化技巧.下面是创建索引的命令:    > db.test.ensureIndex({" ...

  9. js一个抽奖的例子

    朋友公司开年会,帮忙写了个抽奖的demo,源码如下,github中有程序: html: <header> lottery demo </header> <div clas ...

  10. PHP存储blob示例(转)

    原文:http://www.mysqltutorial.org/php-mysql-blob/ <?php /* CREATE TABLE files ( id INT AUTO_INCREME ...