Codeforces Round #811 (Div. 3) D. Color with Occurrences

题目描述:

 

 题目大意:有多组数据,给一个主串和n个字串,问能否用最少的字串完全覆盖主串,若能,输出子串的位置,即是第几个子串覆盖的(按照输入顺序,从1开始)。还有其在主串中的起始位置(从1开始)。若不能则输出-1。

题解:(1)首先根据贪心思想我们可以将主串的每一个位置寻找有没有对应的字串匹配,若有子串匹配则取长度最长的那个子串(在这里可以将初始长度设为-1),记录该主串位置下对应匹配子串的长度和编号。

(2)以上作法可以将主串分为许多个小区间。此时只需寻找最小数量的区间完全覆盖主串即可。对于主串第一个位置若无匹配的字串则直接输出-1。若第一个位置可以匹配,则从第一个位置起,设该区间的左端点为last,则右端点为last+mx【last】-1,对每一个主串的位置i,有它的右端点为i+mx[i]-1。只需找到与上一个区间相交或刚好相连(上一个区间的右端点+1==该区间的左端点)的右端点最大的区间即可。

(3)找到后更新last的位置。如果发现已覆盖区间的右端点==主串长度,直接结束区间覆盖过程。注意这里如果中间出现不匹配的现象,last就无法更新。之后判断已经覆盖区间的右端点是否等于主串长度,小于则输出-1。反之输出结果。

(4)以上大部分是思路,关于代码实现很多细节值得推敲,若有点懵,建议自己在纸上画画,更方便理解。

具体代码实现:

#include <bits/stdc++.h>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define endl '\n'
#define N  205
#define fi first
#define se second
#define pb push_back
using namespace std;
const int inf=0x3f3f3f3f;
const double ex=1e-7;
const int mod=1e9+7;
int gcd(int a ,int b){ return b ? gcd(b,a%b) : a ;}
typedef pair<int,int>PII;
priority_queue<int,vector<int>,greater<int> > q;
string s;
void solve()
{
    int n,num[N],mx[N],len=s.size();
    string k;
    cin >>n;
    for(int i=0;i<=200;i++) mx[i]=-1;
    for(int i=1;i<=n;i++)
    {
        cin >>k;
        int lz=k.size();
        for(int j=0;j<len;j++)
        {
            int t=0;
            while(t<lz&&j+t<len&&k[t]==s[j+t]) t++;
            if(t==lz)
            {
                if(lz>mx[j]) mx[j]=lz,num[j]=i;
            }
        }
    }
    if(mx[0]==-1)
    {
        cout <<-1<<endl;
    }else{
        vector<PII>v;
        int last=0;
        v.pb({num[0],1});
        for(int i=1;i<len;i++)
        {
            if(i<=last+mx[last]&&i+mx[i]-1>last+mx[last]-1)
            {
                int index=i;
                while(i<=last+mx[last]&&i<len)
                {
                    if(i+mx[i]-1>index+mx[index]-1)
                    {
                        index=i;
                    }
                    i++;
                }
                i=index;
                last=index;
                //cout <<last<<endl;
                v.pb({num[index],index+1});
                if(last+mx[last]-1==len-1) break;
            }
        }
        if(last+mx[last]-1<len-1)
        {
            cout <<-1<<endl;
        }else{
            cout <<v.size()<<endl;
            for(auto it : v) cout <<it.fi<<" "<<it.se<<endl;
        }
    }
}
signed main()
{ios
    int t;
    cin >>t;
    while(t--)
    {
        cin >>s;
        solve();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值