#牛客寒假集训营第一场(补题)
(写在前面的话:本次比赛总共解出三道题,貌似是没太大难度那三道,欠缺的主要是字符串方面的,一看到就发蒙)
##D hanayo和米饭
链接:D
来源:牛客网
题目描述
hanayo很喜欢吃米饭。
有一天,她拿出了 个碗,第一个碗装了 粒米饭,第二个碗装了 粒米饭,以此类推,第 个碗装了 粒米饭。
然而,爱搞恶作剧的rin把所有的碗的顺序打乱,并拿走了一个碗。hanayo想知道,rin拿走的碗里有多少粒米饭?
输入描述:
第一行输入一个正整数 。代表原始的总碗数。
第二行输入 个正整数 a_{i}a
i
,代表目前每碗里米饭数量。
保证输入合法。
输出描述:
输出一个正整数,代表rin拿走的碗里米饭数量。
示例1
输入
复制
5
2 5 1 3
输出
复制
4
说明
开始共有5个碗,每个碗内分别有1、2、3、4、5粒米饭。rin拿走的是第四碗。这么简单的样例连tairitsu都看得懂好伐~
思路:水题,不过我做麻烦了,后来看题解,用标记法比较简单。
#include
using namespace std;
int main(){
int n;
int x;
int a[100001];
cin>>n;
for(int i=1;i<n;i++){
cin>>x;
a[x]=1;
}
for(int i=1;i<=n;i++){
if(!a[i]){
cout<<i;
return 0;
}
}
}
##B kotori和bangdream
链接:B
来源:牛客网
题目描述
有一天,kotori发现了一个和lovelive相似的游戏:bangdream。令她惊讶的是,这个游戏和lovelive居然是同一个公司出的!
kotori经过一段时间的练习后已经变得非常触,每个音符 x%x% 的概率perfect,获得 分, (100 -x)%(100−x)% 概率great,获得 分。
已知一首歌有 个音符。kotori想知道,不考虑连击加成的话,一首歌得分的期望是多少?
输入描述:
一行 个整数,用空格隔开。分别是 。
输出描述:
一首歌得分的期望,保留两位小数。
示例1
输入
复制
100 50 500 400
输出
复制
45000.00
说明
如果全perfect是50000分,全great是40000分。由于它们的概率都是50%,即perfect和great五五开,所以期望是45000分。
思路:水题,计算数学期望。
#include
using namespace std;
int main(){
int n,x,a,b;
double source;
cin>>n>>x>>a>>b;
source=a*n*x/100.0+b*n*(100-x)/100.0;
printf("%.2lf",source);
return 0;
}
##E rin和快速迭代
链接:E
来源:牛客网
题目描述
”数论真的太好玩了喵~“——hoshizora rin
rin最近喜欢上了数论。
然而数论实在太复杂了,她只能研究一些简单的问题。
这天,她在研究正整数因子个数的时候,想到了一个“快速迭代”算法。设 为 的因子个数,将 迭代下去,rin猜想任意正整数最终都会变成 。
例如: 。
她希望你帮她验证一下。她会给你一个正整数 ,让你输出它在迭代过程中,第一次迭代成 的迭代次数。
输入描述:
一个正整数
输出描述:
一个正整数,为 迭代至 的次数。
示例1
输入
复制
12
输出
复制
4
说明
12的因子:1,2,3,4,6,12。共6个。
6的因子:1,2,3,6。共4个。
4的因子:1,2,4。共3个。
3的因子:1,3。共2个。
12 → 6 → 4 → 3 → 2 , 故迭代了4次。
思路:这个题其实不算特别难,要注意的就是计算一个数的因子个数时,如果不注意对数据进行处理,容易超时;这就要求在编写计算因子个数的函数时,对时间复杂度进行处理。
#include
using namespace std;
typedef long long ll;
int search(ll n){
int count=0;
for(ll i=1;i*i<=n;i++)//求因子的个数时,i*i减少循环的次数
{
if(n%i==0){
if(n/i==i)
count=count+1;
else
count=count+2;
}
}
return count;
}
int main(){
ll n;
int m;
int j=0;
cin>>n;
m=search(n);
if(m==2)
printf("1");
else
{
while(m!=2)
{
m=search(m);
j++;
}
printf("%d",j+1);
}
return 0;
}
至此,开始补题
先要说一个方法:尺取法,第一次听到,就在网站上找着学。
尺取法:顾名思义,像尺子一样取一段,借用挑战书上面的话说,尺取法通常是对数组保存一对下标,即所选取的区间的左右端点,然后根据实际情况不断地推进区间左右端点以得出答案。尺取法比直接暴力枚举区间效率高很多,尤其是数据量大的时候,所以说尺取法是一种高效的枚举区间的方法,是一种技巧,一般用于求取有一定限制的区间个数或最短的区间等等。当然任何技巧都存在其不足的地方,有些情况下尺取法不可行,无法得出正确答案,所以要先判断是否可以使用尺取法再进行计算。
使用尺取法时应清楚以下四点:
1、 什么情况下能使用尺取法? 2、何时推进区间的端点? 3、如何推进区间的端点? 4、何时结束区间的枚举?
尺取法通常适用于选取区间有一定规律,或者说所选取的区间有一定的变化趋势的情况,通俗地说,在对所选取区间进行判断之后,我们可以明确如何进一步有方向地推进区间端点以求解满足条件的区间,如果已经判断了目前所选取的区间,但却无法确定所要求解的区间如何进一步得到根据其端点得到,那么尺取法便是不可行的。首先,明确题目所需要求解的量之后,区间左右端点一般从最整个数组的起点开始,之后判断区间是否符合条件在根据实际情况变化区间的端点求解答案。
(以上内容转载至原网页尺取法)
##G eli和字符串
链接:G
来源:牛客网
题目描述
eli拿到了一个仅由小写字母组成的字符串。
她想截取一段连续子串,这个子串包含至少 个相同的某个字母。
她想知道,子串的长度最小值是多少?
注:所谓连续子串,指字符串删除头部和尾部的部分字符(也可以不删除)剩下的字符串。例如:对于字符串\mathit{“arcaea”}“arcaea”而言,\mathit{“arc”}“arc”、\mathit“rcae”“rcae”都是其子串。而\mathit“car”“car”、\mathit“aa”“aa”则不是它的子串。
输入描述:
第一行输入两个正整数 和
输入仅有一行,为一个长度为 的、仅由小写字母组成的字符串。
输出描述:
如果无论怎么取都无法满足条件,输出 。
否则输出一个正整数,为满足条件的子串长度最小值。
示例1
输入
复制
5 2
abeba
输出
复制
3
说明
选择\mathit“beb”“beb”子串,长度为3,其中包含相同的两个’b’
本题做法(写的很烂)
#include
#include
using namespace std;
#define N 200005
const int maxx=1000005;
map<char,int>mp;
int main(){
char str[N];
int n,k;
int l,r;
int count;
cin>>n>>k>>str;
for(int i=0;i<n;i++)
mp[str[i]]++;
int ans=maxx;
for(int i=97;i<=123;i++)//遍历26个英文字母;
{
if(mp[i]>=k)//当遍历的字母个数大于k时,开始尺取。
{
l=0;r=0;count=0;//开始时左边右边都为零
if(str[r]==i) count++;
while(1)
{
if(count==k)
{
if(ans>r-l+1)
ans=r-l+1;
if(str[l]==i) count--;//统计完一种情况后,此时由于左边界还在原处,对其判断;
l++; //让左边界右移
}
else
{
if(r==n-1) break;
r++;
if(str[r]==i) count++;
}
}
}
}
//printf("%d\n",ans);
if(ans==maxx)
printf("-1");
else
printf("%d",ans);
return 0;
}
int fastpower(int a,int b,int c){
int ans=1;
a=a%c;
while(b>0){
if(b%2==1)
ans=(ans*a)%c;
b=b/2;
a=(a*a)%c;
}
return ans;
}