HRBU 2021年暑期训练阶段三Day1

目录

A - Similar Strings

题目链接:

题意:

做法:

B - card card card

题目链接:

题意:

做法:

C - String

题目链接:

题意:

做法:

D - Complete the Sequence

题目链接:

题意:

做法:

E - u Calculate e

题目链接:

题意:

做法:

F - Maximum Subrectangle

题目链接:

题意:

做法:

G - Producing Snow

题目链接:

题意:

做法:


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;
}
/**

*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值