牛客练习赛34

A.little w and Soda

题目描述

不知道你听没听说过这样一个脑筋急转弯。

2元可以买一瓶汽水(玻璃瓶装的),因为瓶身是玻璃瓶的比较贵,所以两个瓶身可以换一瓶汽水。你现在有4元钱,问最多能喝到多少瓶汽水?

答案是4瓶。一开始先用4元钱买两瓶汽水喝掉,再用这两瓶的汽水的瓶身换一瓶喝到,最后还剩一个瓶身,这个时候再朝小卖部的老板借一个瓶身。换一瓶汽水喝掉之后再还给他一个瓶身。

现在问题来了,一开始你有n元钱,然后你最多可以向老板借一个瓶身(注意要还的),问你最多能喝到多少瓶汽水?

输入描述:

第一行是一个正整数T(T<=100)表示有T组案例。
对于每组案例,输入一个正整数(1<=n<=10^100)。
(请注意输入数据的范围,n有10的100次方那么大)

输出描述:

对于每组案例,输出一行一个正整数表示最多能够喝到的汽水数目
示例1

输入

3
1
2
1000000000000000000000000000000

输出

0
2
1000000000000000000000000000000

说明

1块钱不能购买汽水,所以共喝到0瓶
2块钱先买一瓶汽水,喝完以后再借一个空瓶,换一瓶,喝掉以后还给老板。所以一共可以喝到2瓶。

备注:

请选用合理的数据类型。
int 型的最大值为2147483647。
long long 型的最大值为9223372036854775807。
float的有效数位为6位。
double的有效数位为12位。
所以本题无法使用以上数据类型处理。
解题思路:字符串简单处理,偶数不变,奇数减1即可。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 int T,len,tmp;string str;
 5 int main(){
 6     while(cin>>T){
 7         while(T--){
 8             cin>>str,len=str.size(),tmp=str[len-1]-'0';
 9             if(tmp&1)str[len-1]--,cout<<str<<endl;
10             else cout<<str<<endl;
11         }
12     }
13     return 0;
14 }

B.little w and Sum

题目描述

小w与tokitsukaze一起玩3ds上的小游戏,现在他们遇到了难关。

他们得到了一个数列,通关要求为这个数列的和为0,并且只有一次改变一个数的符号的机会(正数变成负数,负数变成正数)。

请问小w与tokitsukaze能否通关,如果能,请输出有多少个数符合要求,如果不能,请输出-1。

输入描述:

第一行包括一个正整数n(1≤n≤10^5),表示这个数列有n个数。
接下来一行有n个数x (-100≤x≤100),表示数列(数列的和保证不等于0)。

输出描述:

输出有多少个符合要求的数,如果没有,请输出-1。
示例1

输入

5
1 3 -5 3 4

输出

2

说明

只要把一个3变成-3,数列的和就变为0。数列里总共有两个3,所以有2个符合要求的数。
示例2

输入

4
1 2 4 8

输出

-1
解题思路:先累加所有数字,再暴力判断累加对应出现的个数即可,注意避免重复计数。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 int n,x,sum,cnt;map<int,int> mp;
 5 int main(){
 6     while(cin>>n){
 7         mp.clear(),cnt=sum=0;
 8         for(int i=0;i<n;++i)cin>>x,mp[x]++,sum+=x;
 9         for(map<int,int>::iterator it=mp.begin();it!=mp.end();++it)
10             if(sum-2*it->first==0)cnt+=it->second;
11         cout<<(cnt?cnt:-1)<<endl;
12     }
13     return 0;
14 }

C.little w and Segment Coverage

题目描述

小w有m条线段,编号为1到m。

用这些线段覆盖数轴上的n个点,编号为1到n。

第i条线段覆盖数轴上的区间是L[i],R[i]。

覆盖的区间可能会有重叠,而且不保证m条线段一定能覆盖所有n个点。

现在小w不小心丢失了一条线段,请问丢失哪条线段,使数轴上没被覆盖到的点的个数尽可能少,请输出丢失的线段的编号和没被覆盖到的点的个数。如果有多条线段符合要求,请输出编号最大线段的编号(编号为1到m)。

输入描述:

第一行包括两个正整数n,m(1≤n,m≤10^5)。
接下来m行,每行包括两个正整数L[i],R[i](1≤L[i]≤R[i]≤n)。

输出描述:

输出一行,包括两个整数a b。
a表示丢失的线段的编号。
b表示丢失了第a条线段后,没被覆盖到的点的个数。
示例1

输入

5 3
1 3
4 5
3 4

输出

3 0

说明

若丢失第1条线段,1和2没被线段覆盖到。
若丢失第2条线段,5没被线段覆盖到。
若丢失第3条线段,所有点都被线段覆盖到了。
示例2

输入

6 2
1 2
4 5

输出

2 4

说明

若丢失第1条线段,1,2,3,6没被线段覆盖到。
若丢失第2条线段,3,4,5,6没被线段覆盖到。
解题思路:典型的线段覆盖区间问题,由于数据比较小,直接用差分数组暴力。问题求解的是去掉m条线段中的某一条后使得没有被覆盖的坐标点个数最少,因为若删除了某一条线段后就出现了没被覆盖的点,则说明这些点被线段覆盖的总次数为1,所以用sum数组维护这些点,求一遍前缀和,然后对每一条线段,差分询问更新编号和个数即可。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int maxn=1e5+5;
 5 int n,m,num,id,ans,tmp,cnt[maxn],sum[maxn];
 6 struct node{int x,y;}qry[maxn];
 7 int main(){
 8     while(cin>>n>>m){
 9         id=1,num=0,ans=maxn,memset(sum,0,sizeof(sum)),memset(cnt,0,sizeof(cnt));
10         for(int i=1;i<=m;++i)cin>>qry[i].x>>qry[i].y,cnt[qry[i].x]++,cnt[qry[i].y+1]--;
11         for(int i=1;i<=n;++i)
12             cnt[i]+=cnt[i-1],sum[i]=sum[i-1]+(cnt[i]==1),num+=!cnt[i];///num统计实际没有被线段覆盖的点个数
13         for(int i=1;i<=m;++i)
14             if((tmp=sum[qry[i].y]-sum[qry[i].x-1])<=ans)ans=tmp,id=i;
15         cout<<id<<' '<<ans+num<<endl;
16     }
17     return 0;
18 }
原文地址:https://www.cnblogs.com/acgoto/p/10130853.html