牛客练习赛51 部分题解

牛客练习赛51

A abc

吉首大学校赛原题G,之前写过题解

B 子串查询

题意: 给你一个1e5长度的字符串。Q次查询,每次输入一个子串,求原串是否能正序组成子串?”YES”:”NO”。
思路:

  • O(nlogn)解法,开26个set,每个字母出线的位置按顺序扔进相应set中。然后遍历子串,在每个set中按顺序查询最早出线的位置,位置递增。
  • O(n)解法,nex[1e5][26]表示s串中第i个位置后面第一个字符为(j+’a’)的位置(0<=j<26)。可以用一个队列辅助来求出nex数组,那么,now=nex[now][t[i]-‘a’]。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int INF=0x3f3f3f;
    const int N=1e5+10;
    char s[N];
    set<int>q[26];
    int main()
    {
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
    for(int i=0;i<26;i++)
    q[i].clear();
    scanf("%s",s);
    for(int i=0;s[i]!='\0';i++)
    q[s[i]-'a'].insert(i);
    set<int>::iterator it;
    while(m--)
    {
    scanf("%s",s);
    int flag=1,id=0;
    for(int i=0;s[i]!='\0';i++)
    {
    it=q[s[i]-'a'].lower_bound(id);
    if(it!=q[s[i]-'a'].end())
    id=(*it)+1;
    else flag=0;
    }
    if(flag) puts("YES");
    else puts("NO");
    }
    }
    return 0;
    }
    /*
    abcaa
    aabc
    */

C 勾股定理

原题:关于基本勾股数规律的探讨总结与例题!

D 羊吃草

题意:400头羊在长度为400的数轴上吃草,每头羊可以选择自己喜爱的区间任意一个整点吃草,现在400次查询,每次查询一个区间求这个区间最多可以有多少头羊同时吃草。
思路:匹配问题,每个点可以被很多羊吃,那么建图。查询一个区间[l,r]则遍历每个点,跑匈牙利算法即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f;
const int N=405+10;
struct node
{
int l,r;
} a[N];
int dp[N][N];
int used[N],linked[N];
int n,q;
bool dfs(int u)
{
for(int i=1; i<=n; i++)
if(dp[u][i])
{
if(!used[i])
{
used[i]=1;
if(linked[i]==-1||dfs(linked[i]))
{
linked[i]=u;
return true;
}
}
}
return false;
}
int main()
{
while(~scanf("%d%d",&n,&q))
{
for(int i=1; i<=n; i++) scanf("%d",&a[i].l);
for(int i=1; i<=n; i++) scanf("%d",&a[i].r);
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
for(int j=a[i].l; j<=a[i].r; j++)
dp[j][i]=1;
int l,r;
while(q--)
{
scanf("%d%d",&l,&r);
memset(linked,-1,sizeof(linked));
int ans=0;
for(int i=l; i<=r; i++)
{
memset(used,0,sizeof(used));
if(dfs(i)) ans++;
}
printf("%d\n",ans);
}
}
return 0;
}

考虑到时间性价比,后面的题就不去思考了。放上题解