目录
A - Jessica's Reading Problem
题目链接:
HRBU 2021年暑期训练阶段三Day2 - Virtual Judge
题意:
一个女孩子要复习,一个喜欢她的男孩子帮她把知识点都整理好了,在同一本书上有着许多的索引(也就是页号),且代表了每一页上含有的内容量,问女孩子该去看多少页书才能看完这本书,注意是阅读连续的一部分
做法:
题意晦涩难懂,说白了,就是数组中如何才能用最少的遍历数去遍历数组中所有的数据,因此用set去记录数组中不同的数字的个数,其次规定左右边界,拓展右边界,用map去标记不同的数字是否已经出现过,最后记录答案
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<string> #include<string.h> #include<cstdlib> #include<fstream> #include<queue> #include<stack> #include<map> #include<set> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll maxn=1e5+10; int n,a[maxn],ans=0; set<int> cnt; map<int,int>mp; int main() { ios::sync_with_stdio(false); scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",&a[i]); cnt.insert(a[i]); } int l=0,r=0,sum=0,ans=inf; while(1) { while(r<n&&sum<cnt.size()) { if(mp[a[r++]]++==0) sum++; } if(sum<cnt.size()) break; ans=min(ans,r-l); if(--mp[a[l++]]==0) sum--; } printf("%d\n",ans); return 0; } /** */
B - Bound Found
题目链接:
HRBU 2021年暑期训练阶段三Day2 - Virtual Judge
题意:
给定一个数组,要求求出一段连续的子序列且子序列的和的绝对值最接近t,然后输出子序列的和以及左右边界值
做法:
图示:
由图示可见我们需要求取的连续子序列的和,可以由该数组求前缀和然后由前缀和数组的两个端点相减得到答案,因此,我们需要处理怎么存取前缀和和下标位置以及该去怎么遍历数组,前缀和以及下标可以使用pair进行存储,遍历过程则可以设定左右边界,在移动边界的同时可以进行区间和的判断,需要注意的是区间移动退出后,可能会出现左边界大于右边界的情况,所以需要特殊判断一下,将左右边界对调
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<string> #include<string.h> #include<cstdlib> #include<fstream> #include<queue> #include<stack> #include<map> #include<set> #include<cmath> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll maxn=1e5+10; int T,n,k,t; int a[maxn]; pair<int,int> sum[maxn]; void slove() { cin>>T; int l=0,r=1,minn=inf,ans,L,R; while(r<=n&&minn) { int tmpsum=sum[r].first-sum[l].first; if(abs(tmpsum-T)<=minn) { minn=abs(tmpsum-T); ans=tmpsum; L=sum[l].second; R=sum[r].second; } if(tmpsum<T) r++; if(tmpsum>T) l++; if(l==r) r++; } if(L>R) swap(L,R); cout<<ans<<" "<<L+1<<" "<<R<<endl; } int main() { while(cin>>n>>k&&n&&k) { sum[0]=make_pair(0,0); int tmp=0; for(int i=1;i<=n;i++) { int x; cin>>x; tmp+=x; sum[i]=make_pair(tmp,i); } sort(sum,sum+n+1); for(int i=1;i<=k;i++) slove(); } return 0; } /** */
C - Subsequence
题目链接:
HRBU 2021年暑期训练阶段三Day2 - Virtual Judge
题意:
给定数组,求最小长度的连续子序列的和且和大于等于S,数组内所有数据都小于等于10000且大于等于10
做法:
与B题类似,并且不需要去记录下标的位置,只需要求个数。老办法,设定左右边界,一边移动边界一边进行判断,当个数大于n时,输出0
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<string> #include<string.h> #include<cstdlib> #include<fstream> #include<queue> #include<stack> #include<map> #include<set> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll maxn=1e5+10; int T,n,s; int a[maxn]; int main() { cin>>T; while(T--) { cin>>n>>s; for(int i=0;i<n;i++) cin>>a[i]; int ans=inf,sum=0,l=0,r=0; while(1) { while(r<n&&sum<s) sum+=a[r],r++; if(sum<s) break; ans=min(ans,r-l); sum-=a[l],l++; } if(ans>n) ans=0; cout<<ans<<endl; } return 0; } /** */
D - Tallest Cow
题目链接:
HRBU 2021年暑期训练阶段三Day2 - Virtual Judge
题意:
一堆奶牛排成一排,每一头奶牛的高度都是固定的,已知最高的奶牛的高度以及下标位置,当输入给定两个下标时,说明了这两个位置的奶牛是同等的高度的以及这个区间内的其他奶牛都要比这两头边界牛要矮,求所有奶牛的高度
做法:
图示:
题目样例解释如图所示,根据解释的样例我们能很明显的发现,当输入的区间没有操作过时,我们就对这个区间进行操作,如果区间已经是操作过的(就像4 3 这个例子)我们就不对内部数据在进行操作了,其次对于每一位上的加减操作可以转化为对于某一段区间端点的加减操作,减少时间复杂度,使用map嵌套pair进行操作会更加的方便,在存储坐标的同时还能判断该区间是否操作过
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<string> #include<string.h> #include<cstdlib> #include<fstream> #include<queue> #include<stack> #include<map> #include<set> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll maxn=1e5+10; int N,I,H,R; map<pair<int,int>,bool> judge; int vis[maxn],ans[maxn]; int main() { ios::sync_with_stdio(false); cin>>N>>I>>H>>R; for(int i=1;i<=R;i++) { int A,B; cin>>A>>B; if(A>B) swap(A,B); if(judge[make_pair(A,B)]) continue; vis[A+1]--,vis[B]++; judge[make_pair(A,B)]=true; } for(int i=1;i<=N;i++) { ans[i]=ans[i-1]+vis[i]; cout<<H+ans[i]<<endl; } return 0; } /** 5 4 5 3 5 4 5 5 5 1 3 5 3 4 3 3 7 9 8 */
E - Straight Master
题目链接:
HRBU 2021年暑期训练阶段三Day2 - Virtual Judge
题意:
给出n种数,每种数有a[i]个,每3-5种连续的数都可以被消去,现在问给出的所有数字最后能否全部消去
做法:
本身还是没有非常理解该题的做法,只能说是知道用差分,为什么用,用在哪?说实话不理解,推荐阅读以下博客
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<string> #include<string.h> #include<cstdlib> #include<fstream> #include<queue> #include<stack> #include<map> #include<set> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll maxn=2e5+10; int T,N; ll a[maxn],d[maxn]; int main() { scanf("%d",&T); for(int ca=1;ca<=T;ca++) { scanf("%d",&N); memset(a,0,sizeof(a)); memset(d,0,sizeof(d)); for(int i=1;i<=N;i++) scanf("%lld",&a[i]); for(int i=1;i<=N+1;i++) d[i]=a[i]-a[i-1]; int r=4,flag=0; for(int l=1;l<=N+1;l++) { while(d[l]>0) { while(r<=N+1&&d[r]>=0) r++; if(r>N+1||r-l<3) { flag=1; break; } if(d[r]+d[l]>=0) { d[l]+=d[r]; d[r]=0; } else { d[r]+=d[l]; d[l]=0; } } if(flag) break; } if(flag) printf("Case #%d: No\n",ca); else printf("Case #%d: Yes\n",ca); } return 0; } /** */
F - 非常男女
题目链接:
HRBU 2021年暑期训练阶段三Day2 - Virtual Judge
做法:
其实还是求连续子序列的和,输出的还是个数,将输入的0,1,更改为1,-1会更好的计算和处理
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<string> #include<string.h> #include<cstdlib> #include<fstream> #include<queue> #include<stack> #include<map> #include<set> using namespace std; typedef long long ll; const ll maxn=1e5+10; int n,P[maxn],ans=0; int S[maxn]; int main() { cin>>n; for(int i=1;i<=n;i++) { cin>>P[i]; if(P[i]==0) P[i]=-1; S[i]=S[i-1]+P[i]; } for(int i=1;i<=n;i++) { for(int j=0;j<i;j++) { if(S[i]==S[j]) { if(i-j>ans) ans=i-j; break; } } } cout<<ans<<endl; return 0; } /** */
G - 矩形A + B
题目链接:
HRBU 2021年暑期训练阶段三Day2 - Virtual Judge
做法:
一个简单的求个数公式,((N+1)*N/2)*((M+1)*M/2),两边同时求和再相乘
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<string> #include<string.h> #include<cstdlib> #include<fstream> #include<queue> #include<stack> #include<map> #include<set> using namespace std; typedef long long ll; const ll maxn=1e5+10; int main() { int T,N,M; cin>>T; while(T--) { cin>>N>>M; cout<<((N+1)*N/2)*((M+1)*M)/2<<endl; } return 0; } /** */