Color with Occurrences

传送门

题意:

有一个text t, 和n个字符串\(s_1, s_2, s_3, \cdots, s_n\),在一种操作中可以选择其中的一个\(s_i\), \(s_i\)是t的子串,将t中这个位置的字符串进行染色,你要把整个t字符串都染色,并且已经染色的字符串染了色之后还是红色,如果不可以输出-1,如果可以输出,最少需要几步,并且输出每一步用的\(s_i\)的i, 和在第几个位置进行染色


思路:
观察数据范围很小,所以可以直接暴力找到每个\(s_i\), 能够在t中的能够染色的区间,将他们按照l从小到大的顺序,l相同r从小到大的顺序进行排序,排序序后就转为求最小区间覆盖问题,最小区间覆盖问题,只要先把初始0位置取最优,后面的就是不断的贪在符合条件的范围内r最大的,如果r到达了右端点直接跳出,如果最后r没有到达右端点直接 -1


总结:
小范围暴力,染色而且是可以重复的那就相当于区间覆盖问题,要求操作次数最少,那就是最少区间覆盖问题

点击查看代码
#include <bits/stdc++.h>
#define endl '\n'
#define IOS ios::sync_with_stdio(false);
using namespace std;

typedef long long ll;
#define PII pair<pair<ll, ll>, ll>

ll q, n;
string t, s;
struct Interval
{
    ll l, r;
} region[210];

bool check(ll start, string s)
{
    ll lent = t.size() - start;
    ll lens = s.size();
    if (lent < lens)
        return false;
    for (int i = start, j = 0; i < t.size() && j < s.size(); ++i, ++j)
    {
        if (t[i] != s[j])
            return false;
    }
    return true;
}

bool comp(PII x, PII y)
{
    if (x.first.first != y.first.first)
        return x.first.first < y.first.first;
    return x.first.second < y.first.second;
}

int main()
{
    IOS; cin.tie(0), cout.tie(0);
    cin >> q;
    while (q--)
    {
        cin >> t;
        cin >> n;
        vector<PII> v;
        for (int i = 1; i <= n; ++i)
        {
            cin >> s;
            //看看s在t中可以覆盖的区间
            for (int j = 0; j < t.size(); ++j)
            {
                if (check(j, s))
                    v.push_back({ {j, j + s.size() - 1}, i });    //前两个塞区间,后面塞位置
            }
        }

        if (v.size() == 0)
        {
            cout << "-1" << endl;
            continue;
        }
        sort(v.begin(), v.end(), comp);
        if (v[0].first.first != 0)
        {
            cout << "-1" << endl;
            continue;
        }

        int cnt = 0;
        ll l = 1, r = 0;
        int whatcnt = 0;
        while (cnt < v.size() && v[cnt].first.first == 0)   //先讨论l == 1的最大左边界,这个是必须要选的
        {
            if (r < v[cnt].first.second)
            {
                whatcnt = cnt;
                r = max(r, v[cnt].first.second);
            }
            ++cnt;
        }
        ll ans = 0;
        region[++ans].l = v[whatcnt].second, region[ans].r = v[whatcnt].first.first;
        
        bool flag = true;
        for (int i = cnt; i < v.size(); ++i)    //cnt这个点是还没有遍历过的
        {
            ll tempr = r;
            if (tempr == t.size() - 1)  //说明已经到最后了
            {
                break;
            }
            int j = i;
            int whatj = i;
            while (j < v.size() && v[j].first.first <= r + 1)
            {
                if (tempr < v[j].first.second)
                {
                    whatj = j;
                    tempr = max(tempr, v[j].first.second);
                }
                ++j;
            }

            if (j == i)
            {
                flag = false;
                break;
            }

            i = j - 1;
            r = max(r, tempr);
            region[++ans].l = v[whatj].second, region[ans].r = v[whatj].first.first;
        }

        if (r < t.size() - 1 || flag == false)    //特殊判断
        {
            cout << "-1" << endl;
            continue;
        }
        cout << ans << endl;
        for (int i = 1; i <= ans; ++i)
        {
            cout << region[i].l << " " << region[i].r + 1 << endl;
        }   
    }
    return 0;
}
posted @ 2022-08-03 15:12  YUGUOTIANQING  阅读(64)  评论(0)    收藏  举报