CF Global Round 7

CF Global Round 7#

A.构造##

给定一个数n

你现在要构造一个数,数的位数是n,并且它本身不能被每个数字所整除

构造方法:2333...

B.数学##

复原原序列

其实就是简单推理,

a[i]=curmax+b[i],curmax为max{b[k]|k<i}

C.数学##

给定一个序列有n个元素,他们由1到n组成,现在让你把它划分成k段。

这k段总价值是每段中最大值的总和。

求最大值以及当取最大值时划分数。后者取模998244353

前者贪心即可,只要当前数x满足x+k>n,就说明它是一个段中最大的元素

那么这些最大元拎出来后,影响划分方法的无非就是两个最大元之间的元素个数(注意首尾元素必定跟最近最大元元素不参与下面运算)

根据乘法原理,我们可以得到答案

AC记录:

#include<iostream>
#include<cstring>
using namespace std;
#define INF 1e10+5
#define maxn 200005
#define minn -105
#define ld long double;
#define uint unsigned int;
#define ull unsigned long long;

typedef long long ll;
ll mo=998244353;
int main()
{
    cin.tie(0);
    cout.tie(0);
    ios_base::sync_with_stdio(false);
    ll ans1=0,ans2=1,cur=1;
    int n,k;
    int a[maxn],b[maxn];
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    if(n<k)
    {
        cout<<0<<endl;
        return 0;
    }
    bool ok=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]+k>n)ok=1;
        if(ok)
        {
            if(a[i]+k>n)
            {
                ans2*=cur;
                ans2%=mo;
                cur=1;
                ans1+=a[i];
            }
            else cur++;
        }
    }
    cout<<ans1<<" "<<ans2<<endl;
    return 0;
}

D.Manacher(马拉车) KMP##

题意:

给定一个字符串你只能选取他的一个前缀和后缀,使得它拼起来是回文串,

输出长度最长的串

思路:

首先肯定是找两头连续相同最长的串

接下来无非就是找剩下子串当中最长的前缀或者是后缀,使得它是回文串

如何以线性来处理嘞?

(1)manacher(在专题里填坑)

(2)KMP(来自:官方editorial)

注意这里回文串有有一个很重要的特点————前缀性

所以从某种意义上来说它的模式串是确定的,看下它是如何用kmp求的:

我们不妨将所求的string s倒序成a,a=s+"#"+a

假设我们所求回文子串为s1,由于对称性和回文性,那么s1必定出现在这个字符串a的末尾,我们只要求出s1的长度c即可,无非就是从左往右扫,用模式串在匹配串一一对应找到连续子串即可。

如:abac#caba 显然aba匹配成功

kmp的精髓之处就是失配处理上面,如果失配不是直接将c清零,你比如说:

aaabaaaai

他在翻转以后成了

iaaaabaaa

我们看到答案应该是aaabaaa,但是将c清零的做法只能得到aaa

那么我们忽略的问题是什么?

我们忽略的被匹配掉的字符串可能还能作为前缀参与下一次的从头开始的匹配。在上面的例子里aaa一匹配完,接下来目标串的a不匹配模式串中的b。在此时,aaa被匹配成功,说明了aa(此指前两个a)也被匹配成功,同理可推a也被匹配成功(此指第一个a)。那么如果我们保留aa,就可以神奇地发现我们能够继续往下匹配了。

所以,kmp中,我们现在记录pre[i]=j,含义为如果位置i匹配成功,一定说前j个元素之前的元素能够完全匹配(这里字符串下标从0开始计数)

上面的例子中对应的pre[i]如下:

aaabaaaai

012012330

那么好了,怎么存pre[i]?答案其实也很简单,这个过程不就是“自己匹配自己”的过程吗?换一句话说,我们如果将模式串既当作模式串又当作匹配串,那么我们匹配得到的c值,不就是我们想要的匹配个数,不就是pre[i]啊?

所以我们只要简单pre[i]=c即可

AC:

#include<iostream>
#include<cstring>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
#define INF 1e10+5
#define maxn 1000005
#define minn -105
#define ld long double;
#define uint unsigned int;
#define ull unsigned long long;
typedef long long ll;
int okp[maxn];
int pre[maxn];
//核心部分kmp
string check(string s,bool re)
{
    if(!re)reverse(s.begin(),s.end());
    string a=s;
    reverse(a.begin(),a.end());
    a=s+"#"+a;
    ll c=0;
    for(ll i=1;i<a.size();i++)
    {
        while(c!=0&&a[c]!=a[i])
            c=pre[c-1];
        if(a[c]==a[i])c++;
        pre[i]=c;
    }
    s=a.substr(0,c);
    if(!re)reverse(s.begin(),s.end());
    return s;
}

void solve()
{
	    string s;
    vector<char>curline;
    cin>>s;
    int num=0;
    for(int i=0;i<s.size()/2;i++)
    {
        if(s[i]==s[s.size()-1-i])curline.push_back(s[i]),num++;
        else break;
    }
    string s1=check(s.substr(num,s.size()-2*num),1);
    string s2=check(s.substr(num,s.size()-2*num),0);
	    if(s1.size()<s2.size())s1=s2;
    vector<char>::iterator it;
    for(it=curline.begin();it!=curline.end();it++)
        cout<<*it;
    cout<<s1;
    for(it=curline.end()-1;it!=curline.begin()-1;it--)
        cout<<*it;
    cout<<endl;
}
int main()
{
    int t;
    cin>>t;
    for(int i=0;i<t;i++)
    {
        solve();
    }
    return 0;
}

(马拉车版本更在马拉车专题)

posted @ 2020-03-21 16:48  et3_tsy  阅读(135)  评论(0编辑  收藏  举报