比赛链接:牛客小白月赛65_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)

A:牛牛去购物

题意:

给n元钱,有两种商品,价格为a和b,问最少能花到剩多少钱?

思路:

一开始就猜了发结论:min({n % a,n % b,n % a % b,n % b % a})

感觉自己对麻了

然后喜提WA

但是实际上要花到最少并不一定是先把其中一个花到不能再花才考虑另外一个

比如一个反例就是n = 33,a = 4,b = 7

先买a,买到剩1元,就啥都买不了了

先买b,买到剩5元,再买a,买到剩1元

实际上最优解是先买三个a,剩21元,再买3个b,剩0元

看看数据范围都是<=1000的,直接暴力就完事了

第一重循环枚举买a的数量[0,n / a]

第二重循环枚举买b的数量[0,n / a]

判断条件是i * a + j * b <= n

然后一直取min就完事了

代码:

void solve()
{
int ans = 1e18;
int a,b;
cin >> n >> a >> b;
for(int i = 0;i <= n / a;i++)
{
for(int j = 0;j <= n / b;j++)
{
if(i * a + j * b <= n)
{
ans = min(ans,n - i * a - j * b);
}
}
}
cout << ans << endl;
}

总结:

看看数据范围再决定猜结论还是打暴力(

如果能打暴力坚决不猜结论!

B:牛牛写情书

题意:

给一个长度为n的初始字符串和一个长度为m的目标字符串

问初始字符串去掉除开小写字母以外的字符后是否含有目标字符串

思路:

思路很显然,模拟即可

就先用个字符串收集初始字符串中的小写字母

然后再用一下find()函数来判断即可

代码:

void solve()
{
string s1,s2,s3;
cin >> n >> m;
cin >> s1 >> s2;
for(int i = 0;i < n;i++)
{
if(s1[i] >= 'a'&&s1[i] <= 'z') s3 += s1[i];
}
if(s3.find(s2) != -1) YES;
else NO;
}

总结:

A题卡了可以先看看后面的,感觉B比A简单一些(

C:牛牛排队伍

题意:

有一个1到n的排列

有m次操作和询问

操作是去掉排列的某个数字

询问是输出某个数字的前面一个数字,如果这个数字是第一个数字就输出0

思路:

按要求模拟即可

因为涉及到去除数字和查找数字

我选择用set来模拟

查找数字用find()即可

去除数字用erase()即可

代码:

void solve()
{
cin >> n >> m;
set<int> s;
for(int i = 1;i <= n;i++) s.insert(i);
int x,y;
while(m--)
{
cin >> x >> y;
if(x == 1) s.erase(y);
else
{
auto it = s.find(y);
if(it == s.begin()) cout << 0 << endl;
else cout << *prev(it) << endl;
}
}
}

C题总结:

STL容器和函数还是很有用的!

D题:牛牛取石子

题意:

给两堆石子为n和m,石子数为a和b

牛牛先手,牛妹后手

操作有两种

一种为在n堆取1个,m堆取2个

一种为在n堆取2个,m堆取1个

谁先无法取石子谁就输

思路:

最开始考虑先手必胜,咋个都想不出来

后来考虑后手必胜:

如果数量少的那一堆石子%3 == 0的话

不管牛牛咋个取石子

牛妹跟他弄相反的操作即可

这样牛妹是必胜的

反之,如果石子数 % 3 != 0

牛牛只要操作一次使得小的那一堆 % 3 == 0即可

显然这个结论是成立的

然后就喜提WA

如果两个数字是一样的捏

比如 4 4

这种牛牛就做不到必胜了

因为不管咋个操作都会变成 2 3

也就是说如果(两个数字一样的&&小的一堆 % 3 != 0) != 牛牛必胜

原因就是之前的证明都默认了第一次操作不会改变a,b的相对大小

所以这里再判断一下

如果两个数相等且石子数 % 3 == 2 -> 牛牛必胜

如果两个数相等且石子数 % 3 == 1 -> 牛妹必胜

代码:

void solve()
{
cin >> n >> m;
if(n > m) swap(n,m);
if(n % 3 == 0) cout << "niumei" << endl;
else if(n == m)
{
if(n % 3 == 1) cout << "niumei" << endl;
else cout << "niuniu" << endl;
}
else cout << "niuniu" << endl;
}

总结:

后来才知道这种叫做"对称博弈"

就是两种操作是对称的

一般对称博弈都是考虑后手必赢状态

因为后手只要对称着操作

两次操作就会某种形式上的抵消

决定是否抵消的是后手

当然先手也可以通过操作来使得下一次操作变成必输态

这就要根据题来讨论了

E:牛牛的构造

题意:

 
 
 
 
要你构造一个长度为n的排列,并且满足
这个排列恰好有k个二元组
二元组条件为:1 <= i < j <= n&&ai - aj = 2x

思路:

赛事没弄出来(实际根本没去想)

典型的构造题

典型的没思路

先想想极端情况

如果一个排列是从小到大的->0个二元组

如果排列是从大到小的捏

如果数字从n开始,那么后面满足的数字有这些:

n - 1,n - 2,n - 4,n - 8,n - 16.......

因为n - (n - x) = x

由于是个排列,换种方式考虑

n=6时:6 5 4 3 2 1

6 - 5 = 1,6 - 4 = 2,6 - 3 = 3,6 - 2 = 4,6 - 1 = 5

5 - 4 = 1,5 - 3 = 2,5 - 2 = 3,5 - 1 = 4;

......

发现就是对于一个逆序的排列

每个数算贡献的时候考虑的都是[1,p[i] - 1]

那么在[1,p[i] - 1]中的贡献为log2(p[i] - 1) + 1

公式就出来了

打个表:

2    3    4    5    6    7    8    9

1    2    2    3    3    3    3    4

所以如果要构造的n算出来的值如果小于了k

可以直接退出然后输出-1了(因为这已经是最大的情况了)

如果刚好等于k当然可以直接输出逆序的排列

然后就是关于这个值<k了

这题的结论就是如果这个值<k,不管是啥都可以构造出来

不会证明

然后最关键的地方来了((

要做这题就要想个构造方式

这题的构造方式就是:先降后升

比如要构造贡献为11的,n为9的

根据上面打的表

4 + 3 + 3 + 1即可

对应的就是9 8 7 2

然后加上剩余的数

就是9 8 7 2 1 3 4 5 6

可以发现:

对于前面降序的数有这个性质:比这个数小的都在这个数后面

那么可以直接通过上面那个表求出相应的值

而对于后面升序的数来说,已经和前面的数算过贡献,但是后面的数又都比当前位置的数大

所以后面的数贡献都是0

所以结论就是:

只要在算出的那个表中选出几个数字且这几个数之和为k作为前面降序的数就好了

我以为这里要用背包来着

结果从大到小贪心即可

不会证明

代码:

void solve()
{
cin >> n >> m;
if(n == 1)
{
if(m == 0) cout << 1 << endl;
else cout << -1 << endl;
return;
}
int sum = 0;
vector<int> a(n + 10),b(n + 10),st(n + 10);
for(int i = 1;i <= n;i++) a[i] = i;
for(int i = 2;i <= n;i++) b[i] = (int)log2(a[i] - 1) + 1,sum += b[i];
// cout << b[3] << endl;
reverse(all(a));
reverse(all(b));
// for(int i = 1;i <= n;i++) cout << a[i] << " ";
// cout << endl;
// for(int i = 1;i <= n;i++) cout << b[i] << " ";
// cout << endl;
if(sum < m) cout << -1 << endl;
else if(sum == m)
{
for(int i = 1;i <= n;i++) cout << a[i] << " ";
cout << endl;
}
else
{
int res = 0;
for(int i = 1;i <= n;i++)
{
if(res + b[i] <= m)
{
res += b[i];
st[i] = 1;
cout << a[i] << " ";
}
}
for(int i = n;i >= 1;i--)
{
if(!st[i]) cout << a[i] << " ";
}
}
}

总结:

这题感觉非常巧妙((

即使听了思路也是如此

对于这类构造题,先要去考虑一下极端情况,比如最多多少,最少多少

然后再根据极端情况来进行调整

然后再根据性质推出一些结论

但是这题的先降序后升序这里

感觉确实比较人类智慧((

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

牛客小白月赛65ABCD(E)的更多相关文章

  1. 树的最长链-POJ 1985 树的直径(最长链)+牛客小白月赛6-桃花

    求树直径的方法在此转载一下大佬们的分析: 可以随便选择一个点开始进行bfs或者dfs,从而找到离该点最远的那个点(可以证明,离树上任意一点最远的点一定是树的某条直径的两端点之一:树的直径:树上的最长简 ...

  2. 牛客网 牛客小白月赛5 I.区间 (interval)-线段树 or 差分数组?

    牛客小白月赛5 I.区间 (interval) 休闲的时候写的,但是写的心情有点挫,都是完全版线段树,我的一个队友直接就水过去了,为啥我的就超内存呢??? 试了一晚上,找出来了,多初始化了add标记数 ...

  3. 牛客小白月赛8 - E - 诡异数字 数位DP

    牛客小白月赛8 - E - 诡异数字 题意: 求区间中,满足限制条件的数字的个数. 限制条件就是某些数字不能连续出现几次. 思路: 比较裸的数位DP, DP数组开一个dp[len][x][cnt] 表 ...

  4. 牛客小白月赛18 Forsaken给学生分组

    牛客小白月赛18 Forsaken给学生分组 Forsaken给学生分组 链接:https://ac.nowcoder.com/acm/contest/1221/C来源:牛客网 ​ Forsaken有 ...

  5. 牛客小白月赛18 Forsaken喜欢数论

    牛客小白月赛18 Forsaken喜欢数论 题目传送门直接点标题 ​ Forsaken有一个有趣的数论函数.对于任意一个数xxx,f(x)f(x)f(x)会返回xxx的最小质因子.如果这个数没有最小质 ...

  6. 牛客小白月赛19 E 「火」烈火燎原 (思维,树)

    牛客小白月赛19 E 「火」烈火燎原 (思维,树) 链接:https://ac.nowcoder.com/acm/contest/2272/E来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空 ...

  7. 【牛客小白月赛21】NC201604 Audio

    [牛客小白月赛21]NC201604 Audio 题目链接 题目大意: 给出三点 ,求到三点距离相等的点 的坐标. 解析 考点:计算几何基础. 初中蒟蒻表示不会什么法向量.高斯消元..qwq 方法一: ...

  8. 【牛客小白月赛21】NC201605 Bits

    [牛客小白月赛21]NC201605 Bits 题目链接 题目描述 Nancy喜欢做游戏! 汉诺塔是一个神奇的游戏,神奇在哪里呢? 给出3根柱子,最开始时n个盘子按照大小被置于最左的柱子. 如果盘子数 ...

  9. 牛客小白月赛16 小石的妹子 二分 or 线段树

    牛客小白月赛16 这个题目我AC之后看了一下别人的题解,基本上都是线段树,不过二分也可以. 这个题目很自然就肯定要对其中一个进行排序,排完序之后再处理另外一边,另一边记得离散化. 怎么处理呢,你仔细想 ...

  10. 牛客小白月赛6 E 对弈 思维

    链接:https://www.nowcoder.com/acm/contest/136/E来源:牛客网 题目描述 善弈者谋势,不善弈者谋子.                               ...

随机推荐

  1. nginx启停shell脚本

    #!/bin/bash # 编写 nginx 启动脚本 # 本脚本编写完成后,放置在/etc/init.d/目录下,就可以被 Linux 系统自动识别到该脚本 # 如果本脚本名为/etc/init.d ...

  2. 测试Thread中的常用方法:

    测试Thread中的常用方法:start():启动当前线程:调用当前线程的run()run(): 通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中currentThread ...

  3. do-while循环的使用

    一.循环结构的4个要素 ① 初始化条件 ② 循环条件 --->是boolean类型 ③ 循环体 ④ 迭代条件 二.do-while循环结构: ①do{ ③; ④;}while(②); 执行过程: ...

  4. 抓包分析 TCP 握手和挥手

    前言 首先需要明确的是 TCP 是一个可靠传输协议,它的所有特点最终都是为了这个可靠传输服务.在网上看到过很多文章讲 TCP 连接的三次握手和断开连接的四次挥手,但是都太过于理论,看完感觉总是似懂非懂 ...

  5. CF240F (26颗线段树计数)

    题目链接:Topcoder----洛谷 题目大意: 给定一个长为n的由a到z组成的字符串,有m次操作,每次操作将[l,r]这些位置的字符进行重排,得到字典序最小的回文字符串,如果无法操作就不进行. 思 ...

  6. 聊聊kafka

    两个月因为忙于工作毫无输出了,最近想给团队小伙伴分享下kafka的相关知识,于是就想着利用博客来做个提前的准备工作了:接下来会对kafka做一个简单的介绍,包括利用akf原则来解析单机下kafk的各个 ...

  7. C语言实现计算“已经活了多少天”

    输入生日,通过系统或者自己输入,获得当前日期,计算已经存活了多少天. #include<stdio.h> #include<time.h> /** * 函数介绍: * 通过输入 ...

  8. 第2-3-1章 文件存储服务系统-nginx/fastDFS/minio/阿里云oss/七牛云oss

    目录 文件存储服务 1. 需求背景 2. 核心功能 3. 存储策略 3.1 本地存储 3.2 FastDFS存储 3.3 云存储 3.4 minio 4. 技术设计 文件存储服务 全套代码及资料全部完 ...

  9. Xtrabackup使用帮助

    目录 1.安装工具 2.下载后上传到需要备份的服务器 全备 1.安装完成后我们进行数据库备份执行以下命令 2.查看备份的数据 3.进入数据库,删除一个测试库 4.删除school库 5.备份数据目录 ...

  10. 深入理解Golang 闭包,直通面试

    大家好 今天为大家讲解的面试专题是: 闭包. 定义 闭包在计算机科学中的定义是:在函数内部引用了函数内部变量的函数. 看完定义后,我陷入了沉思...确实,如果之前没有接触过闭包或者对闭包不理解的话,这 ...