目录
A - Similar Strings
题目链接:
HRBU 2021年暑期训练阶段三Day1 - Virtual Judge
题意:
给定两个字符串,问在k个字母不相同的情况下,两个字符串中存在相同的子串的最大长度是多少
例如:
3 qwertypoi qwetyrio
在运行3个字母不同的情况下,最长的子串为qwerty和qwetyr,从第4位开始两个子串的字母不相同,所以最大的子串长度就是6
做法:
把两个字符串依次遍历,先把第一个串作为子串到第二个串中进行遍历,然后锁定一个最大值,接着再用后一个串作为子串到第一个串中遍历,和上一个答案相比较取最大
#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=5010; int t,k,ans; char s1[maxn],s2[maxn]; void slove(char *s1,char *s2) { int len=min(strlen(s1),strlen(s2)); int l=0,r=0,cnt=0; for(int i=0;i<len;i++) { while(r<len) { if(s1[r]!=s2[r]) { if(cnt+1>k) break; cnt++; } r++; } ans=max(ans,r-i); if(s1[i]!=s2[i]) cnt--; } } int main() { scanf("%d",&t); while(t--) { ans=0; scanf("%d",&k); scanf("%s%s",s1,s2); int len=strlen(s1); for(int i=0;i<len;i++) slove(s1+i,s2); len=strlen(s2); for(int i=0;i<len;i++) slove(s2+i,s1); printf("%d\n",ans); } return 0; }
B - card card card
题目链接:
HRBU 2021年暑期训练阶段三Day1 - Virtual Judge
题意:
两个boy玩卡牌游戏,他们都有可以把前面的卡牌放到后面的权利,每一张牌都有一个惩罚值,每移动一次卡牌就会获得卡牌上的值且得到这张牌,但是相应的就要减去这张卡牌对应的惩罚值,如果手里有的卡牌值小于惩罚值,那么游戏就结束了,问挪动几次卡牌你才能获得最大的一个卡牌数量
做法:
每一次移动都是加上一个值再减去一个值,所以运用一个前缀和的思想,每一次都进行加减操作然后记下一个累和,要是这个和已经小于0了,说明前面的值已经不足以满足条件了,就更新和为0,记录一下更新位置就ok了(因为数据水的很,所以不同担心爆时间)
#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=1e6+10; int n,a[maxn],b[maxn]; int main() { while(scanf("%d",&n)!=EOF) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]); ll ans=0; int cnt=1; for(int i=1;i<=n;i++) { ans+=(ll)(a[i]-b[i]); if(ans<0) cnt=i+1,ans=0; } printf("%d\n",cnt-1); } return 0; }
C - String
题目链接:
HRBU 2021年暑期训练阶段三Day1 - Virtual Judge
题意:
给定一个字符串,问串中包含k个不同字母组合的子串有几个?(位置不同也算)
例如:
abcabcabcabc 3
子串的形式有:abc 因为位置不同,所以共有55个不同的子串
做法:
尺取法,把左边界确定下来,然后去统计不同字母的个数,当个数满足要求时,这就是最短的子串长度,接下来用总长度减去右边界+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=1e6+10; int t,k; ll ans=0; int vis[30]; char s[maxn]; int main() { scanf("%d",&t); while(t--) { memset(vis,0,sizeof(vis)); scanf("%s%d",s,&k); int n=strlen(s),i=0,j=0,sum=0; ans=0; while(1) { while(j<n&&sum<k) { if(!vis[s[j]-'a']) sum++; vis[s[j]-'a']++; j++; } if(sum<k||j>n) break; ans+=n-j+1; vis[s[i]-'a']--; if(!vis[s[i]-'a']) sum--; i++; } printf("%lld\n",ans); } return 0; }
D - Complete the Sequence
题目链接:
HRBU 2021年暑期训练阶段三Day1 - Virtual Judge
题意:
给定你一个序列,要求算出这个序列的后C个数字
做法:
用数学角度来说,这个叫做拉格朗日公式(可惜没听懂)所以我们采用粗人的方式来理解
推到两个样例:
图示:
左边是两个比较典型的样例推导,我们对于要进行求数字的序列进行差分化,求出该序列的差分数组(也叫作一阶差分)当这个差分满足只有一个数据或者是全都是一个常数时,我们就可以由这个差分数组往回进行一个序列的累加推导,就可以求出我们想到得出的序列后C位数字了
#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=110; int T,S,C,num[maxn][maxn]; int main() { cin>>T; while(T--) { cin>>S>>C; for(int i=0;i<S;i++) cin>>num[0][i]; for(int i=1;i<S;i++) { for(int j=0;j<S-i;j++) num[i][j]=num[i-1][j+1]-num[i-1][j]; } for(int i=1;i<S+C;i++) num[S-1][i]=num[S-1][0]; for(int i=S-2;i>=0;i--) { for(int j=S-i;j<S+C;j++) num[i][j]=num[i+1][j-1]+num[i][j-1]; } cout<<num[0][S]; for(int i=1;i<C;i++) cout<<" "<<num[0][S+i]; cout<<endl; } return 0; }
E - u Calculate e
题目链接:
HRBU 2021年暑期训练阶段三Day1 - Virtual Judge
题意:
就是运用题中给的公式进行累和计算
做法:
按照公式写两个数组模拟就行
#include <cstdio> using namespace std; int main() { int i; printf("n e\n"); printf("- -----------\n"); double a[10],b[10]; int c[10]; a[0]=c[0]=1; for(int i=1;i<10;i++) { c[i]=c[i-1]*i; b[i]=c[i]*1.0; } for(int i=1;i<10;i++) a[i]=a[i-1]+(1.0/b[i]); for(int i=0;i<10;i++) { if(i==0) printf("0 1\n"); if(i==1) printf("1 2\n");; if(i==2) printf("2 2.5\n");; if(i>2) printf("%d %.9lf\n",i,a[i]); } return 0; }
F - Maximum Subrectangle
题目链接:
HRBU 2021年暑期训练阶段三Day1 - Virtual Judge
题意:
给你一个长度为n的数列a和长度为m的数列b,定义c(i,j)=ai*bj,得到c矩阵,给定值x,求c矩阵中的子矩阵和小于等于x的最大的元素个数
做法:
将两个数组a,b进行前缀和处理,然后再去计算Cij,o(n^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 int INF = 0x3f3f3f3f; const ll maxn=2021; ll n,m,ans; ll a[maxn],b[maxn]; ll suma[maxn],sumb[maxn]; int main() { while(scanf("%lld%lld",&n,&m)!=EOF) { memset(suma,INF,sizeof(suma)); memset(sumb,INF,sizeof(sumb)); a[0]=b[0]=0; for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]+=a[i-1]; for(int i=1;i<=m;i++) scanf("%lld",&b[i]),b[i]+=b[i-1]; int x; scanf("%d",&x); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(j+i-1>n) break; suma[i]=min(suma[i],a[j+i-1]-a[j-1]); } } for(int i=1;i<=m;i++) { for(int j=1;j<=m;j++) { if(j+i-1>m) break; sumb[i]=min(sumb[i],b[j+i-1]-b[j-1]); } } ans=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(suma[i]*sumb[j]<=x) { ans=max(ans,i*j*1ll); } } } printf("%lld\n",ans); } return 0; }
G - Producing Snow
题目链接:
HRBU 2021年暑期训练阶段三Day1 - Virtual Judge
题意:
给定两个数组,第一个数组表示有n堆雪,每堆雪都有Vi的质量,第二个数组表示每天都会融化掉Ti质量的雪,如果当天Vi<Ti则那天消耗的质量就是Vi,问每一天消耗的雪的质量是多少
做法:
主要考虑两个地方:
1、这堆雪是在哪一天会全部融化结束,最后融化的时候是否满足当天融化的Ti
2、每天的融化量都是已知的,所以只需要判断当天雪的Vi是否满足Ti,如果满足就数量+1,否则就直接加上就好了
对融化量T数组进行一个前缀和处理即可
#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,V[maxn], T[maxn], num[maxn]; ll sum[maxn], ans[maxn]; int main() { cin>>N; for(int i=1;i<=N;i++) cin>>V[i]; for(int i=1;i<=N;i++) { cin>>T[i]; sum[i]=sum[i-1]+T[i]; } for(int i=1;i<=N;i++) { int x=upper_bound(sum+1,sum+N+1,V[i]+sum[i-1])-sum; ans[x]+=(V[i]+sum[i-1]-sum[x-1]); num[i]++; num[x]--; for(int j=1;j<=N;j++) cout<<ans[j]<<" "; cout<<endl; } ll tmp=0; for(int i=1;i<=N;i++) { tmp+=num[i]; cout<<ans[i]+tmp*T[i]<<" "; } cout<<endl; return 0; } /** */