Codeforces Round#674div.3 CDEF

C

题目

题目链接
刚开始给你一个数组为[1],。你每次可以有如下两种操作:
(1) 从数组中选择任意一个数字,并分裂成两个一模一样的数。
(2) 从数组中选择一个数加1。
例如,现在你有五次操作的机会。
第一次,把第一个数分裂,变成[1,1]。
第二次,把第一数加1操作,[2,1]。
第三次,把第二个数分裂,[2,1,1]。
第四次,把第一个数分裂,[2,1,1,2]。
第五次,把第四个数加1,[2,1,1,3]。
五次后数组元素总和为2+1+1+3 = 7.
你的任务是消耗最少的次数使得数组的总和大于等于n。
Input
输入的第一行包含一个整数t(1≤t≤1000)–测试用例的数量。然后,t个测试用例随之而来。
测试用例的唯一一行包含一个整数n(1≤n≤1000000000)–总和。
Output
对于每个测试用例,打印答案:获得数组总和至少为n的最少操作次数。
Example
Input
4
1
5
42
1000000000
Output
0
3
11
63244

分析

题目让我们求最少的次数,那么如何才能使得次数最少呢,也就是说怎样才能最优呢?与其又增加又复制,还不如直接增加a[1]到一定程度,然后再复制。试想一下,如果我们把数提前就复制了几份,那么我们再增加的时候是该增加哪个呢?这无疑是增加了我们的次数。总之,乘是1次,加是1次,肯定优先用乘。
然后就是实现部分了,如何知道+到什么时候转换成*呢?先采取最暴力的做法,我们从头开始枚举,算一下+到2的时候再乘需要多少次,+到3的时候再乘需要多少次······但是n的范围1e9,还有个t<=1000,怎么降低时间复杂度呢?我们发现,没有必要从1枚举到n,因为我们枚举到一定地步的时候,后面就不是最优了,所以我们仅枚举到根号n即可~

#include<string>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
 
const int N=0x3f3f3f3f;
 
using namespace std;
int t,n;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        int len=sqrt(n),ans=N;//sqrt是为了降低时间复杂度,之后的枚举已没有了意义
        for(int i=1;i<=len;i++)
        {
            int num=i;//自增,自增所需要的次数为num-1
            int res=n/num+(n%num==0?0:1);//这里还要再判断一下是否整除
            ans=min(ans,num-1+res-1);//所以这里就是(num-1)+(res-1),取遍历后最小的次数
        }
        printf("%d ",ans);
    }
    return 0;
 
}

D

题目

鲜花学长喜欢1,因为他平时收到消息时会回复别人1,所以他非常不喜欢0,他的目标是消灭数组中所有的0, 有一个数组a,其中不存在a_i=0,但是丧心病狂的它觉得这还不能够满足 即使是这个数组的任意子段(subsegment)的和为0也是它不能接受的。 他可以往数组中的任意位置插入任意大小的数(注意是任意大小,包括无穷大),请问最少插入几个数后才能成为鲜花学长的理想数组(即不存在子段和为0的情况)
Input
第一行为数组元素个数n∈[2,200 000] 第二行为n个元素a_i∈[-109,109],a_i≠0
Output
输出需要最少插入数字的个数
Examples
Input
4
1 -5 3 2
Output
1
Input
5
4 -2 3 -9 2
Output
0
Input
9
-1 1 -1 1 -1 1 1 -1 -1
Output
6
Input
8
16 -5 -11 -15 10 5 4 -4
Output
3
Note
第一个样例中,我们发现只有一个子段的和为0 即 1 -5 3 2 我们可以在-5和3之间插入9,之后它就成为鲜花学长的理想数组 故答案为1

题目大意

给一个数组,可以向数组中的位置插入任意的数,求最少插几次可以使得数组中没有子区间和为0的区间

知识点

前缀和,STL

分析

某个区间和=sum[R]-sum[L-1]
区间和为0:sum[R]-sum[L-1]=0即sum[R]=sum[L-1],所以我们求出每个前缀和,统计前缀和相等的个数,和前缀和为0的个数即可
注意:
1、提前将0加入到要统计的序列中
2、当我们插入一个数的时候,后面的区间前缀和已经发生了改变,需要我们重新进行求取

题目链接

#include <map>
#include <string>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
	
using namespace std;
	
const int maxn = 2e5 + 10;
	
long long a[maxn],sum[maxn];
	
int n;
	
	// 注意数据范围 
map<long long,int>maps;
	
int main() {
  scanf("%d",&n);
  for(int i = 1; i <= n; i ++) {
	scanf("%lld",&a[i]);
  }
  int ans = 0;
  maps[0] = 1;
  sum[1] = a[1];
  maps[sum[1]] = 1;
  for(int i = 2; i <= n; i ++) {
  sum[i] = sum[i - 1] + a[i];
	// 插入一个数后,需要重新进行统计
      if(maps[sum[i]]) {
		ans ++;
		maps.clear();
		sum[i] = a[i];
		maps[sum[i]] = 1;
		maps[0] = 1;
	} else {
		maps[sum[i]] = 1;
		}
	}
	printf("%d\n",ans);
	return 0;
} 

E

题意

alice和bob玩剪刀石头布, 他们玩的次数n次,已知alice出了a1个石头、a2个剪刀、a3个布,bob出了b1个石头、b2个剪刀、b3个布,现在你可以调整他们的出拳顺序,问alice最少赢了多少次,最多赢了多少次。 其中 a1+a2+a3=b1+b2+b3=n ( 1<=n<=10^9)

intput
n
a1 a2 a3
b1 b2 b3
Input
2
0 1 1
1 1 0
Output
0 1
Input
15
5 5 5
5 5 5
Output
0 15
Input
3
0 0 3
3 0 0
Output
3 3
Input
686
479 178 29
11 145 530
Output
22 334
Input
319
10 53 256
182 103 34
Output
119 226
题目链接

分析

自行体会,我也解释不清,就觉得这样做是对的(狗头)

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,a,b,c,d,e,f;
    cin>>n>>a>>b>>c>>d>>e>>f;
    cout<<n-min(a,n-e)-min(b,n-f)-min(c,n-d)<<" "<<min(a,e)+min(b,f)+min(c,d);
    return 0;
}

F

ps:

拿到题目手抖是怎么回事嘛?别自己吓自己好么宝,贴贴~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值