算法刷题day11

目录

  • 引言
  • 一、FEB
  • 二、区间合并
  • 三、管道
  • 四、填充

引言

今天是初四,已经休息三天了,今天开始继续学习,然后觉得确实玩久了不太适应,已经有惰性了,不过还好自己喜欢,还是慢慢的坚持了下来,本来今天要看理论课的,也没看成,玩手机没停下来,不过好在做了些题,慢慢来吧。


一、FEB

标签:数学

思路:自己只能想出个暴力过了一半的数据,然后标准答案见示例代码2

题目描述:

有一个长度为 N 的字符串 S,其中的每个字符要么是 B,要么是 E。

我们规定 S 的价值等于其中包含的子串 BB 以及子串 EE 的数量之和。

例如,BBBEEE 中包含 2 个 BB 以及 2 个 EE,所以 BBBEEE 的价值等于 4。

我们想要计算 S 的价值,不幸的是,在我们得到 S 之前,约翰将其中的一些字符改为了 F。

目前,我们只能看到改动后的字符串 S,对于其中的每个 F,我们并不清楚它之前是 B 还是 E。

请你计算,改动前的 S 有多少种可能的价值并将所有可能价值全部输出。

输入格式
第一行包含一个整数 N。

第二行包含改动后的字符串 S。

输出格式
第一行输出一个整数 K,表示改动前的 S 的可能价值的数量。

接下来 K 行,按照升序顺序,每行输出一个可能价值。

数据范围
1≤N≤2×105
输入样例1:
4
BEEF
输出样例1:
2
1
2
输入样例2:
9
FEBFEBFEB
输出样例2:
2
2
3
输入样例3:
10
BFFFFFEBFE
输出样例3:
3
2
4
6

示例代码1:DFS

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

string str;
unordered_map<int,int> map;
vector<int> res;

int get()
{
    int res = 0;
    for(int i = 1; i < str.size(); ++i)
    {
        if(str[i] == str[i-1])
        {
            res++;
        }
    }
    
    return res;
}

void dfs(int u)
{
    if(u == str.size())
    {
        //cout << str << endl;
        int t = get();
        if(!map.count(t))
        {
            map[t]++;
            res.push_back(t);
        }
        return;
    }
    
    if(str[u] != 'F')
    {
        dfs(u+1);
        return;
    }
    
    
    str[u] = 'B';
    dfs(u+1);
    
    
    str[u] = 'E';
    dfs(u+1);
    str[u] = 'F';  // 这里一定要加上不然后面遍历后,再从前面开始这块就不是'F'了
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    int n;
    cin >> n;
    cin >> str;
    
    dfs(0);
    
    sort(res.begin(), res.end());
    cout << res.size() << endl;
    for(int x: res)
    {
        cout << x << endl;
    }
    
    return 0;
}

示例代码2:

#include 
#include 
#include 

using namespace std;

int n;
string s;

int main()
{
    cin >> n >> s;
    
    if(s == string(n, 'F'))
    {
        cout << n << endl;
        for(int i = 0; i < n; ++i)
            cout << i << endl;
    }
    else
    {
        int l = 0, r = n - 1;
        while(s[l] == 'F') l++;
        while(s[r] == 'F') r--;
        
        int low = 0, high = 0;
        auto str = s;
        for(int i = l; i <= r; ++i)
        {
            if(str[i] == 'F')
            {
                if(str[i-1] == 'B') str[i] = 'E';
                else str[i] = 'B';
            }
            if(i > l && str[i] == str[i-1]) low++;
        }
        
        str = s;
        for(int i = l; i <= r; ++i)
        {
            if(str[i] == 'F') str[i] = str[i-1];
            if(i > l && str[i] == str[i-1]) high++;
        }
        
        int ends = l + n - 1 - r, d = 2;
        if(ends) high += ends, d = 1;
        
        cout << (high - low) / d + 1 << endl;
        for(int i = low; i <= high; i += d)
            cout << i << endl;
    }
    
    return 0;
}

二、区间合并

标签:区间合并

思路:模板题没什么说的,马上就用了,熟悉一下

题目描述:

给定 n 个区间 [li,ri],要求合并所有有交集的区间。

注意如果在端点处相交,也算有交集。

输出合并完成后的区间个数。

例如:[1,3] 和 [2,6] 可以合并为一个区间 [1,6]。

输入格式
第一行包含整数 n。

接下来 n 行,每行包含两个整数 l 和 r。

输出格式
共一行,包含一个整数,表示合并区间完成后的区间个数。

数据范围
1≤n≤100000,−109≤li≤ri≤109
输入样例:
5
1 2
2 4
5 6
7 8
7 9
输出样例:
3

示例代码:

#include 
#include 
#include 

using namespace std;

const int N = 1e5+10;

struct Len
{
    int l, r;
    bool operator<(const Len& other)
    {
        return l < other.l;
    }
}len[N];
int n;

int main()
{
    scanf("%d", &n);
    
    for(int i = 0; i < n; ++i)
    {
        scanf("%d%d", &len[i].l, &len[i].r);
    }
    
    sort(len, len+n);
    
    int res = 0;
    int l = -2e9, r = -2e9;
    for(int i = 0; i < n; ++i)
    {
        if(len[i].l > r)
        {
            res++;
            l = len[i].l;
            r = len[i].r;
        }
        else
        {
            r = max(r, len[i].r);
        }
    }
    
    cout << res << endl;
    
    return 0;
}

三、管道

标签:二分、区间合并

思路:就是给一条长为 m m m 的管子,每个管子中间有一个阀门和水流检测器,给出特定阀门打开的编号和时间,算能够使得所有监视器都检测到水的最短时间。明显这时间越长肯定能通过,所以单调性用二分,然后就是check条件了,假设最短时间为 m i d mid mid ,则会有多个区间代表水能够流通的管道编号,要做的就是把这些区间找出来,然后合并,看是否能够合并成从 [ 1 , m ] [1,m] [1,m] 的一个区间

题目描述:

有一根长度为 len 的横向的管道,该管道按照单位长度分为 len 段,每一段的中央有一个可开关的阀门和一个检测水流的传感器。

一开始管道是空的,位于 Li 的阀门会在 Si 时刻打开,并不断让水流入管道。

对于位于 Li 的阀门,它流入的水在 Ti(Ti≥Si)时刻会使得从第 Li−(Ti−Si) 段到第 Li+(Ti−Si) 段的传感器检测到水流。

求管道中每一段中间的传感器都检测到有水流的最早时间。

输入格式
输入的第一行包含两个整数 n,len,用一个空格分隔,分别表示会打开的阀门数和管道长度。

接下来 n 行每行包含两个整数 Li,Si,用一个空格分隔,表示位于第 Li 段管道中央的阀门会在 Si 时刻打开。

输出格式
输出一行包含一个整数表示答案。

数据范围
对于 30% 的评测用例,n≤200,Si,len≤3000;对于 70% 的评测用例,n≤5000,Si,len≤105;
对于所有评测用例,1≤n≤105,1≤Si,len≤109,1≤Li≤len,Li−1

示例代码:

#include 
#include 
#include 

using namespace std;

const int N = 1e5+10;

typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y second

int n, m;
PII w[N], q[N];

bool check(int mid)
{
    int cnt = 0;
    for(int i = 0; i < n; ++i)
    {
        int L = w[i].x, S = w[i].y;
        if(mid >= S)
        {
            int t = mid - S;
            int l = max(1, L - t), r = min((LL)m, (LL)L + t);
            q[cnt++] = {l,r};
        }
    }
    
    sort(q, q+cnt);
    
    int l = -1, r = -1;
    for(int i = 0; i < cnt; ++i)
    {
        if(q[i].x > r + 1) l = q[i].x, r = q[i].y;
        else r = max(r, q[i].y);
    }
    
    return l == 1 && r == m;
}

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; ++i) scanf("%d%d", &w[i].x, &w[i].y);
    
    int l = 0, r = 2e9;
    while(l < r)
    {
        int mid = (LL)l + r >> 1;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    
    printf("%d\n", r);
    
    return 0;
}

四、填充

标签:贪心

思路:这个跟FEB区别在于没有重叠,所以可以用贪心的方式

题目描述:

有一个长度为 n 的 01 串,其中有一些位置标记为 ?,这些位置上可以任意填充 0 或者 1,请问如何填充这些位置使得这个 01 串中
出现互不重叠的 00 和 11 子串最多,输出子串个数。

输入格式
输入一行包含一个字符串。

输出格式
输出一行包含一个整数表示答案。

数据范围
对于所有评测用例,1≤n≤106。

输入样例:
1110?0
输出样例:
2
样例解释
如果在问号处填 0,则最多出现一个 00 和一个 11:111000。

示例代码:

#include 
#include 

using namespace std;

const int N = 1e6+10;

string str;

int main()
{
    ios::sync_with_stdio(false); cin.tie(0);
    
    cin >> str;
    
    int res = 0;
    for(int i = 1; i < str.size(); ++i)
    {
        if(str[i] == str[i-1] || str[i] == '?' || str[i-1] == '?')
        {
            i++;
            res++;
        }
    }
    
    printf("%d\n", res);
    
    return 0;
}

你可能感兴趣的:(#,算法刷题,算法,深度优先,c++)