hitoli717

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

(自用)[USACO2023-JAN-Bronze] T1 LEADERS 题解

题目描述

农夫约翰有 \(N(2≤N≤10^5)\) 头奶牛,每一头奶牛的品种是更赛牛G或荷斯坦牛H中的一种。
每一头奶牛都有一个名单,第 \(i\) 头奶牛的名单上记录了从第 \(i\) 头奶牛(即自己)到第 \(E_i (i≤E_i≤N)\) 头奶牛的连续所有奶牛。每一种奶牛都有且仅有一位“领导者”,对于某一头牛 \(i\),如果它能成为“领导者”仅当它满足以下条件的至少一个:

  • 其记录的名单上包含它的品种的所有奶牛。
  • 其记录的名单上记录了另一品种奶牛的“领导者”。

请求出有多少对奶牛可能成为两种奶牛的领导者,保证存在至少一种。

输入输出

输入

第一行包含一个整数 N;
第二行包含一个长度为N的字符串,第i个字符表示第i头牛的种类(G=Guernsey , H=Holstein). 数据确保至少有一头G和一头H;
第三行包含N个整数,表示E1,……,En。

输出

一个整数,表示有多少对可行的头领。

样例

样例输入1
4
GHHG
2 4 3 4
样例输入2
3
GGH
2 3 3
样例输出1
1
样例输出2
2

数据范围和约定:

Inputs 3-5: N≤100
Inputs 6-10: N≤3000
Inputs 11-17: No additional constraints.

题解

看到题目首先想到的是暴力破解的方法,遍历所有的牛,对每头牛分别验证条件1和条件2:

  • 对条件1,遍历名单以外的所有牛,如果没有出现跟自己品种相同的牛,就设为首领;
  • 对条件2,我们有每个奶牛的数对 \((i,E_i)\) ,每次要把某个奶牛 \(j\) 设为首领时,检查 \(j\) 是否落在某个区间 \([i,E_i]\) 内。

显然这样的方法复杂度至少要 \(O(n^2)\) 以上,对于 \(N≤10^5\) 的数量级会 \(TLE\) ,需要优化。
通过分析成为leader的条件可以发现,若想满足条件1,必要条件是:该奶牛是所在种类第一头出现的奶牛。因为 \(i≤E_i≤N\) ,后面出现的奶牛名单不可能包含前面出现的,若不是第一头出现的,它就不可能包含编号在它前面的同族奶牛,也就不可能包含同族所有奶牛,也就不满足条件1了。而由于题目中给出至少存在一对可以知道每种奶牛的第一头必然是头领
其实题目里还暗含了一个条件。两种奶牛出现有先后顺序,后出现的那种奶牛,有且仅有一头牛是首领,而且必是出现的第一头。后出现的奶牛只能满足条件1,不可能满足条件2。因为根据上面奶牛leader规律的分析,在它后面的奶牛已经不可能满足条件1,又根据前面对后出现种类奶牛leader规律的分析,也不可能满足条件2了。所以我们只计算第一次出现的那种奶牛有几个可能的leader,就是可能的奶牛对数。

代码

(来不及写代码调了,直接贴别人的了,优化思路就是受到这个启发的)
[USACO2023-JAN-Bronze] T1 LEADERS 题解

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n;
char s[N];
int a[N];
int main() {
    scanf("%d%s",&n,s+1);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int pos,last;
    for(int i=2;i<=n;i++){
        if(s[i]!=s[1]){        //找位置靠后种类奶牛的第一个位置
            pos=i;break;
        }
    }
    for(int i=1;i<=n;i++){
        if(s[i]==s[1]){        //第一头种类奶牛的最后一个位置
            last=i;
        }
    }
    int ans=0;
    for(int i=1;i<pos;i++){
        if((i==1&&a[i]>=last)||a[i]>=pos)
            ans++;
    }
    printf("%d",ans);
    return 0;
}
posted on 2024-12-20 19:41  Hitoli  阅读(42)  评论(0)    收藏  举报