牛客练习赛51

https://ac.nowcoder.com/acm/contest/1083#question

A、 abc

题意:

给出一个字符串s,你需要做的是统计s中子串”abc”的个数。子串的定义就是存在任意下标a<b<c,那么”s[a]s[b]s[c]”就构成s的一个子串。如”abc”的子串有”a”、”b”、”c”、”ab”、”ac”、”bc”、”abc”。

输入描述:

一个字符串s。保证输入只包含小写拉丁字符。
1<=|s|<=1e5

输出描述:

一个整数表示s中子串”abc”的个数。

示例1

输入

abcabc

输出

4

思路:递推思想,水题

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3fLL
using namespace std;
ll a,ab,abc,n;
string s;
int main()
{
    cin>>s;
    n=s.size();
    for(int i=0;i<n;i++)
    {
        if(s[i]=='a') a++;
        else if(s[i]=='b') ab+=a;
        else if(s[i]=='c') abc+=ab;
    }
    cout<<abc<<endl;
}

B、字串查询

题目描述

给出一个长度为n的字符串s和q个查询。对于每一个查询,会输入一个字符串t,你需要判断这个字符串t是不是s的子串。子串的定义就是存在任意下标a<b<c<d<e,那么”s[a]s[b]s[c]s[d]s[e]”就构成s的一个子串。如”abc”的子串有”a”、”b”、”c”、”ab”、”ac”、”bc”、”abc”。

输入描述:

第一行两个数n,q。1<=n,q<=1e5。

第二行一个长度为n的字符串s,所有字符都为小写拉丁字符。

接下来q行每行一个字符串t。1<=|t|<=50。

输出描述:

对于每个查询,如果t是s的字串,输出”YES”,否则输出”NO”。每个答案占一行。

示例1

输入

 

8 4
ababcbaa
abac
accb
aaaa
abcba

输出

 

YES
NO
YES
YES

思路:因为太长,无法直接匹配,因为只有26个小写字母,可以记录其位置,然后依次查询符合条件的尽可能的左边的位置。

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3fLL
#define maxn 100010
using namespace std;
int q,n,k;
char s[maxn],t[55];
vector<int>v[30];
void init()
{
    for(int i=0;i<n;i++)
    {
        v[s[i]-'a'].push_back(i);
    }
    return;
}
int fin(int fa,int rt)
{
    int l=0,r=v[rt].size(),mid=-1;
    while((l+r)/2!=mid)
    {
        mid=(l+r)/2;
        if(v[rt][mid]>fa) r=mid;
        else l=mid;
    }
    if(r>=v[rt].size()) return -2;
    return v[rt][r]>fa?v[rt][r]:-2;
}
int main()
{
    scanf("%d%d",&n,&q);
    scanf("%s",s);
    init();
    while(q--)
    {
        scanf("%s",t);
        k=strlen(t);
        int l=-1;
        for(int i=0;i<k;i++)
        {
            l=fin(l,t[i]-'a');
            if(l==-2) {break;}
        }
        if(l==-2) printf("NO\n");
        else printf("YES\n");
    }
}
C题是个结论题,身为数学系的我不会。。。

D、羊吃草

 

题目描述

有一个草原可以用一个1~400的数轴表示。有n头羊和q个查询。每头羊的编号分别是1,2,3…n。第i头羊只喜爱数轴上[ai,bi]这样的一个闭区间,每一时刻每头羊只可能在自己喜爱的区间的某个点上吃草。现在给出q个查询,每个查询两个整数l,r。你需要计算出在同一时刻,最多能有多少头羊同时在这个区间内吃草。数轴上每一个整点同一时刻只能容纳一只羊,羊只会在整点吃草。

输入描述:

第一行三个数n q。

第二行n个数a1 a2…an。

第三行n个数b1 b2…bn。

接下来q行每行两个数l,r。表示询问的区间。

输出描述:

对于每个查询,输出一个整数表示答案。

示例1

输入

 

5 3
1 1 1 2 4
1 1 1 3 5
1 5
2 5
1 3

输出

 

3
2
2

备注:

1<=n,q<=400

1<=ai<=bi<=400

1=l<=r<=400

思路:先讲样的区间按左端点排序,对于当前询问区间,依次从左到右每个位置安排羊吃草,左端点<=当前位置的,将其右端点加入multiset,multiset内的羊一定是可以在当前点吃草的,安排的最优是右端点小的那只,贪心思想吧。(开完班会回来有继续写的,中间断思路 了,所以写的很乱,但是1A,哈哈,胆大,过样例就交,但是讲真写的有些乱!)

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3fLL
#define maxn 500
using namespace std;
struct AA
{
    int l,r,rt;
    bool operator <(const AA&aa) const
    {
        return l<aa.l;
    }
}pos[maxn];
int n,q,l,r;
bool cmp(AA aa,AA bb)
{
    return aa.rt<bb.rt;
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&pos[i].l);
        pos[i].rt=i;
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&pos[i].r);
    }
    sort(pos+1,pos+n+1);
    while(q--)
    {
        scanf("%d%d",&l,&r);
        multiset<int>s;
        multiset<int>::iterator it;

        int a=l,ans=0,c;
        for(int i=1;i<=n&&a<=r;)
        {
            while(pos[i].l<=a&&i<=n) {s.insert(pos[i].r);i++;}
            while(!s.empty())
            {
                it=s.begin();
                c=(*it);
                //cout<<c<<endl;
                if(c<a) s.erase(s.begin());
                else break;
            }
            if(!s.empty())
            {
                ans+=1;
                a++;
                s.erase(s.begin());
               // cout<<i<<" ! "<<ans<<" "<<s.size()<<endl;
                //system("pause");
            }
            else
            {
                a=pos[i].l;
            }
            while(!s.empty())
            {
                it=s.begin();
                c=(*it);
                //cout<<c<<endl;
                if(c<a) s.erase(s.begin());
                else break;
            }
        }
        while(!s.empty()&&a<=r)
        {
            it=s.begin();
            c=(*it);
            if(c>=a) {s.erase(s.begin());ans++;a++;}
            while(!s.empty())
            {
                it=s.begin();
                c=(*it);
                //cout<<c<<endl;
                if(c<a) s.erase(s.begin());
                else break;
            }
        }
        printf("%d\n",ans);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值