连续子序列
给定一个长度为N(10<N<100000)的正整数序列。每个正整数都小于等于10000,给定一个正整数S(S<100000000)。编写一个程序找到一个最小长度的子序列,要求这个子序列的和大于等于S。如果解不存在,则输出0。
输入格式
第一行两个整数N和S,第二行包括n个正整数表示数列A,两两之间用空格分隔。
输出格式
一个符合题目要求的整数。
输入/输出例子1
输入:
5 11
1 2 3 4 5
输出:
3
代码:
#include<bits/stdc++.h>
using namespace std;
long long a[10000005],sum,s,n,ans;
int main(){
cin>>n>>s;
for(int i=0;i<n;i++)
cin>>a[i];
int tou=0,wei=0,ans=10000000,sum=0;
while(1)
{
while(wei<n&&sum<s)
sum+=a[wei++];
if(sum<s)break;
ans=min(ans,wei-tou);
sum-=a[tou++];
}
if(ans==10000000)cout<<0;
else cout<<ans;
return 0;
}
最小和
输入N个数的数列,所有相邻的M个数的和共有N-M+1个,求其中的最小值。
输入格式
第1行,2个整数N,M,范围在[3…100000],N>M。
第2行,有N个正整数,范围在[1…1000]。
输出格式
1个数,表示最小和。
输入/输出例子1
输入:
6 3
10 4 1 5 5 2
输出:
10
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,m,s,a[100005],mins=0x7f7f7f7f7f7f7f7f;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int L=1,R=1;R<=n;R++)
{
s+=a[R];
if(R-L+1==m)
{
mins=min(mins,s);
s=s-a[L];
L++;
}
}
cout<<mins;
return 0;
}
求和为C
楠楠在网上刷题,感觉第一题:求两数的和(A+B Problem)太无聊了,于是增加了一题:求和为C的Problem,难倒了一群小朋友,哈哈。 题目是这样的:给出N个正整数,一个值C,要求在这N个整数中找一段连续的数(至少2个数),使得它们的和等于C,问这样的方案有多少种? 例如:N=8,C=7,8个整数是:2 5 1 1 2 4 7 1。答案是3。具体方案:(2, 5)、(5,1,1)、(1,2,4)。
输入格式
第一行2个正整数:N,C。
第二行:N个正整数。
数据范围:N的范围是[1…100,000]。C的范围是[1…1,000,000,000]。N个整数中每个数的范围是:[1…1,000,000,000]。
输出格式
一个整数,表示该串数中包含的所有方案数。
输入/输出例子1
输入:
4 5 1 4 1 4
输出:
3
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,k,a[100005],s[100005],ans;
int main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
s[i]=s[i-1]+a[i];
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(s[j]-s[i-1]==m)
ans++;
if(s[j]-s[i-1]>=m)
break;
}
}
printf("%d\n",ans);
return 0;
}
附一道同一类型的题
差
楠楠在网上刷题,感觉第一题:求两数的和(A+B Problem)太无聊了,于是增加了一题:A-B Problem,难倒了一群小朋友,哈哈。
题目是这样的:给出 N 个从小到大排好序的整数,一个差值 C,要求在这 N个整数中找两个数 A 和 B,使得 A-B=C,问这样的方案有多少种?
例如:N=5,C=2,5 个整数是:2 2 4 8 10。答案是 3。具体方案:第3个数减第 1 个数;第 3 个数减第 2 个数;第 5 个数减第 4 个数。
输入格式
第一行 2 个正整数:N,C。
第二行 N 个整数:已经有序。注意:可能有相同的。
输出格式
一个整数,表示该串数中包含的所有满足 A-B=C 的数对的方案数。
输入/输出例子1
输入:
4 1
1 1 2 2
输出:
4
样例解释
5 个数据:N 的范围是[1…1,000]。
5 个数据:N 的范围是[1…100,000]。
所有数据:
C 的范围是[1…1,000,000,000]。
N 个整数中每个数的范围是:[0…1,000,000,000]。
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,c,a,t;
map<long long,long long>b;
int main()
{
cin>>n>>c;
for(int i=1;i<=n;i++)
{
cin>>a;
if(c<=a)t+=b[a-c];
b[a]++;
}
cout<<t;
return 0;
}
黑白奶牛
有N只奶牛从左往右排成一行,编号是1至N。这N只奶牛当中,有一些奶牛是黑色的,其余的是白色的。
color[i]表示第i只奶牛的颜色,如果color[i]=0则表示第i头奶牛是黑色的,如果color[i]=1则表示第i头奶牛是白色的。
六一奶牛儿童节快到了,农场主Farmer John要从这N头奶牛当中,挑选尽可能多的奶牛去参加晚会。
Farmer John挑选奶牛的原则是:挑选编号是连续的一段奶牛,这一段奶牛的颜色必须全部是白色的。
Farmer John有一个魔法棒,每用一次魔法棒就可以把一头黑色的奶牛变成一头白色的奶牛,魔法棒最多只能使用K次。在上述条件下,最多可以有多少头奶牛去参加晚会呢?
输入格式
第一行,两个整数,N和K。
第二行,N个整数,第i个整数就是color[i],color[i]要么是0,要么是1。
输出格式
一个整数,表示最多有多少头奶牛可以去参加晚会。
数据规模
对于50%的数据,1<=N<=1000,K=0,即不能使用魔法棒。
对于100%的数据,1<=N<=100000,1<=K<=N。
输入/输出例子1
输入:
11 0
1 1 0 0 1 1 1 1 0 1 1
输出:
4
输入/输出例子2
输入:
11 1
1 1 0 0 1 1 1 1 0 1 1
输出:
7
样例解释
样例1 由于 K=0,所以不能使用魔法棒, 所以挑选编号是 5 至 8 的奶牛去参加晚会
样例2 由于 K=1,所以最多可以使用 1 次 魔法棒,使用魔法棒把第 9 头奶牛 变成白色奶牛,然后挑选编号是 5 至 11 的奶牛去参加晚会。
代码:
#include<bits/stdc++.h>
using namespace std;
int a[100010],n,k,l=1,r=1,ans=0,sum=0;
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
while(r<=n)
{
if(!a[r++])sum++;
while(sum>k)
if(!a[l++])sum--;
ans=max(ans,r-l);
}
cout<<ans;
return 0;
}
拔河比赛
今天小Q班的体育课,是进行拔河比赛。同学们个个兴奋极了。体育老师一声令下,就抢着拉绳子占好了位置,谁也不肯让谁。
每位同学都一个力量值,为了让两边队伍实力均衡,体育老师想找一个合适的“中点”,将队伍分成两边,使得两个队伍力量总值相差最小。你来帮体育老师想想办法?
输入格式
第一行有两个正整数。一个整数N(2 <= N <= 500000),表示小Q班上的人数。
第二行有N个整数,依次表示队伍中每位同学的力量值P(0<=p<=1000)。
输出格式
输出两个数x和y。 表示在x和y之间设置“中点”,可以使队伍两边的力量总值相差最小(如果有多个中点,则以x大优先)。
输入/输出例子1
输入:
10
65 50 80 85 120 95 85 55 75 120
输出:
5 6
样例解释
前5个人的力量和为400,后5个人的力量和为430,最小差值为30。
数据范围:
对于60%的数据 N<10000;
对于100%的数据 N<500000;
代码:
#include<iostream>
using namespace std;
int a[1001000],b[1001000];
long long n,sum,num,maxx,f;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
for(int i=1;i<=n;i++)
{
num+=a[i];
b[i]=abs(sum-num-num);
}
maxx=b[1];
f=1;
for(int i=1;i<n;i++)
{
if(maxx>=b[i])
{
maxx=b[i];
f=i;
}
}
cout<<f<<" "<<f+1;
return 0;
}
射箭
FJ很喜欢看射箭比赛,看着运动员们一个个精湛的技艺,令他头晕目眩膜拜不已。而且他喜欢给那些射箭选手打分,他想如果一位选手能在尽量短的时间段内射出所有可能的环数,那么他的得分就是那段最短时间的长度。
现在,FJ告诉你其中一位选手共射出了n支箭,当然他每个单位时间射出一只箭。FJ还会告诉你他射出的每支箭的环数。而且环数总共的可能性有m种,环数分别为1-m,请你帮他算过这位选手在他心目中的分数。
输入格式
输入文件共两行
第一行两个数n,m。
第二行一共n个数表示那位选手每一箭的环数。
输出格式
输出文件只有一个数,表示这位选手的得分。如果这位运动员无法在这n箭中射出所有的环数,则输出-1。
输入/输出例子1
输入:
12 5
2 5 3 1 3 2 4 1 1 5 4 3
输出:
6
样例解释
说明:这位选手从第2支箭到第7支箭射出了所有可能的环数,因此他的得分是6。
数据范围
30% n<=1000 m<=20
100% n<=1000000 m<=2000
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000005],b[2005],ans,minn=1000000001;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int x=1,y=1;y<=n;y++)
{
b[a[y]]++;
if(b[a[y]]==1) ans++;
while(ans==m)
{
minn=min(minn,y-x+1);
b[a[x]]--;
if(b[a[x]]==0)ans--;
x++;
}
}
if(minn!=1000000001)cout<<minn;
else cout<<"-1";
return 0;
}
收集数据
幼儿园的N名(N为偶数)小朋友们排成一列,每个人手中都拿有一个数据fi,两位老师分别站在队首和队尾。一个从队首往中间走,一位从队尾往中间走,他们俩走的节奏始终一致,直到相遇为止。在行进的过程中,他们每人可以收集连续K个小朋友手上的数据,但必顺在同一时刻开始,同一时刻结束。求这个过程被收集的数据之和最大可能是多少。
输入格式
幼儿园的N名(N为偶数)小朋友们排成一列,每个人手中都拿有一个数据fi,两位老师分别站在队首和队尾。一个从队首往中间走,一位从队尾往中间走,他们俩走的节奏始终一致,直到相遇为止。在行进的过程中,他们每人可以收集连续K个小朋友手上的数据,但必顺在同一时刻开始,同一时刻结束。求这个过程被收集的数据之和最大可能是多少。
输出格式
输出为一行,是一个整数,为被收集的小朋友手中数据之和的最大值。
输入/输出例子1
输入:
8 2 1 1 5 1 2 4 3 1
输出:
13
代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,a[1000005],sum,b[1000005],num,maxx;
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=a[i]+b[i-1];
}
for(int i=1,j=i+k-1,x=n,y=x-k+1;j<y;i++,j++,x--,y--)
maxx=max(maxx,(b[j]-b[i-1])+b[x]-b[y-1]);
cout<<maxx;
return 0;
}
最少页数
为了准备比赛,华华开始读一本很厚的书本。要想通过考试,必须把书本中所有的知识点都掌握。这本书共有P页,每一页都有一个知识点Ai。全书中同一个知识点可能会被多次提到,所以他希望通过阅读其中连续的一些页把所有的知识点都覆盖到。请你求出要阅读的最少页数。
输入格式
第一行,1个整数P,1<=P<=10^6
第二行,P个正整数Ai,1<=Ai<=10^6
输出格式
输出要阅读的最少页数
输入/输出例子1
输入:
5
1 8 8 8 1
输出:
2
样例解释:
只需要阅读第一页和第二页即可
代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[1000005],b[1000005],tou=0,wei=0,c[1000005],sum,s,bj=1000000000;
int main(){
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
if(b[a[i]]==0){b[a[i]]=1,sum++;}
}
for(tou=0,wei=0;wei<n;wei++)
{
if(c[a[wei]]==0)s++;
c[a[wei]]++;
while(s==sum)
{
bj=min(bj,wei-tou+1);
c[a[tou]]--;
if(c[a[tou]]==0)
s--;
tou++;
}
}
cout<<bj;
return 0;
}
最短子串
给出字符串S,字符串的每一个字符是’1’或’2’或’3’。你要从S中选取一段连续字符,不妨假设这段连续的字符构成的字符串是T,你的目标是使得T的长度最短,而且字符’1’、’2’、’3’在T中都出现过。如果无法完成目标则输出0,否则输出T的最短长度。
输入格式
一个字符串S,长度不超过200000。
输出格式
一个整数。
输入/输出例子1
输入:
112233
输出:
4
数据范围
对于60%的分数,S的长度不超过100。
代码:
#include<bits/stdc++.h>
using namespace std;
string a;
int tou=0,wei=0,c[1000005],sum=3,s,bj=1000000000;
int main(){
cin>>a;
for(tou=0,wei=0;wei<a.size();wei++)
{
if(c[int(a[wei])]==0)s++;
c[int(a[wei])]++;
while(s==sum)
{
bj=min(bj,wei-tou+1);
c[int(a[tou])]--;
if(c[int(a[tou])]==0)
s--;
tou++;
}
}
cout<<bj;
return 0;
}