牛客练习赛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 }