Codeforces Global Round 7(马拉车)

Codeforces Global Round 7

  • D1 Prefix-Suffix Palindrome(EASY)
  • D2 Prefix-Suffix Palindrome(HARD)
  • A Bad Ugly Numbers
  • B Maximums
  • C Permutation Partitions

Codeforces Global Round 7

D1 Prefix-Suffix Palindrome(EASY)

题意:给定字符串s,在s中取前缀a、后缀b,要求a+b组成回文串t(a、b可以为空串),同时t的长度不能超过s。求最大长度的t并输出。简单版本的s长度1e5

:一开始脑子不太好使直接上暴力,结果n3直接tle。憨憨还在那里以为哪个地方死循环了(超不自信患者)

思路:因为规定了t只能由前缀和后缀组成,也就是说,a的起始点下标一定是0,b的末点下标一定是len。a与b顺序相接
所以从两边开始找对称的最大,直接加到a上,这一段是固定的(前后缀)。然后就在剩下的中间段上找前后缀中的最大回文串。(暴力)

想不清楚可以看看样例里的第二个:

abcdfdcecba
a中固定的:abc
中间段:dfdce

代码中间while(1)根本没用是sbbbb的产物

int check(string ss){
    int l=-1,r=ss.length();
    while(ss[l+1]==ss[r-1]&&l+1<=r-1){
        l++;
        r--;
    }
    if(l==r||l+1==r)
        return 1;
    else
        return 0;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        string s,a,ans;
        cin>>s;
        s.insert(0,"0");
        s+='0';
        int l,r;
        while(1){
            int len=s.length()-2;
            //cout<<"111 "<
            l=0,r=len+1;
            while(s[l+1]==s[r-1]&&l+1<r-1){
                l++;
                r--;
            }
            if(l==0){
                for(int i=len;i>=1;i--){
                    string tt,rtt;
                    tt+=s.substr(1,i);
                    rtt+=s.substr(len+1-i,i);
                    //cout<<"222 "<
                    if(check(tt)){
                        string b;
                        b+=a;
                        reverse(b.begin(),b.end());
                        ans=a+tt+b;
                        break;
                    }
                    if(check(rtt)){
                        string b;
                        b+=a;
                        reverse(b.begin(),b.end());
                        ans=a+rtt+b;
                        break;
                    }
                }
                break;
            }
            a+=s.substr(1,l);
            if(len-2*l==0){
                string b;
                b+=a;
                reverse(b.begin(),b.end());
                ans=a+b;
                break;
            }
            string temp;
            swap(temp,s);
            s+='0';
            s+=temp.substr(l+1,len-2*l);
            s+='0';
        }
        cout<<ans<<endl;
    }
    return 0;
}

D2 Prefix-Suffix Palindrome(HARD)

题意:和easy版本一样,但是字符串的数据范围扩大到了1e6,暴力试探回文串基本上是爆了的。

思路:优化中间段的回文串判断,把o(n2)降到o(n).
manacher
这是一个不成熟的连接

大半夜cf突然判不了这个代码我不知道过没过啊
re一波以后过了哈哈我服了ts一定要开char类型,要不manacher会越界

int cnt[maxn*2];
char ts[maxn*2];
void manacher(string s,int len){
    int l=0;
    ts[l++]='$';
    ts[l++]='#';
    for(int i=0;i<len;i++){
        ts[l++]=s[i];
        ts[l++]='#';
    }
    ts[l]=0;
    int maxr=0,flag=0;
    for(int i=0;i<l;i++){
        cnt[i]=maxr>i?min(cnt[2*flag-i],maxr-i):1;
        while(ts[i+cnt[i]]==ts[i-cnt[i]])
            cnt[i]++;
        if(i+cnt[i]>maxr){
            maxr=i+cnt[i];
            flag=i;
        }
    }
    return;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        string s,a,ans;
        cin>>s;
        s.insert(0,"0");
        s+='0';
        int l,r;
        while(1){
            int len=s.length()-2;
            //cout<<"111 "<
            l=0,r=len+1;
            while(s[l+1]==s[r-1]&&l+1<r-1){
                l++;
                r--;
            }
            if(l==0){
                string tt=s.substr(1,len);
                manacher(tt,len);
                int maxxp=0,maxxn=0;
                for(int i=1;i<=2*len;i++){
                    if(cnt[i]==i){
                        maxxp=max(maxxp,cnt[i]-1);
                    }
                    if(i+(cnt[i]-1)==2*len+1){
                        maxxn=max(maxxn,cnt[i]-1);
                    }
                }
                string b;
                b+=a;
                reverse(b.begin(),b.end());
                if(maxxp>maxxn)
                    ans=a+tt.substr(0,maxxp)+b;
                else ans=a+tt.substr(len-maxxn,maxxn)+b;
                break;
            }
            a+=s.substr(1,l);
            if(len-2*l==0){
                string b;
                b+=a;
                reverse(b.begin(),b.end());
                ans=a+b;
                break;
            }
            string temp;
            swap(temp,s);
            s+='0';
            s+=temp.substr(l+1,len-2*l);
            s+='0';
        }
        cout<<ans<<endl;
    }
    return 0;
}

A Bad Ugly Numbers

题意:给定n为输出数字的长度,要求输出的数字不能被其中出现过的数字整除。

ex:6(×)能被6整除 12(×)能被1、2整除

思路:简单构造题,A我想的是用5和4,用4结尾就保证不被5整除,4前面加个5就能保证不被4整除。B看了其他代码有用2和3的,开头一个2其余全是3,保证奇性同时不被3整除

int main(){
    int t=ird();
    while(t--){
        int n=ird();
        if(n==1){
            cout<<-1<<endl;
            continue;
        }
        if(n%2==0){
            for(int i=1;i<=n/2;i++)
                cout<<"54";
            cout<<endl;
        }
        else
        {
            for(int i=1;i<=n/2;i++)
                cout<<"45";
            cout<<"4"<<endl;
        }
    }
    return 0;
}
 

B Maximums

不想说辽我好困

int a[maxn],b[maxn];
int main(){
    int n=ird();
    for(int i=1;i<=n;i++){
        b[i]=ird();
    }
    int maxx=0;
    for(int i=1;i<=n;i++){
        maxx=max(maxx,a[i-1]);
        a[i]=b[i]+maxx;
        cout<<a[i]<<" ";
    }
    cout<<endl;
    return 0;
}

C Permutation Partitions

题意:给定1-n的排列,取k个不相交区间。让所有区间的最大值相加最大,输出最大值和不同分区数量。

思路:组合数学。取的区间最大数字为n~n-k+1,第一个答案就是等差数列求和。现在问题就转化成了:已经把选定的数字放在了数组中,如何分区?
下标和数字大小记录,按数字大小排列。分区数就是中间数字个数的乘积。(手推一下就好)

struct node{
    LL num;
    LL id;
}a[maxn];
bool cmp(node aa,node ab){
    return aa.num>ab.num;
}
int main(){
    LL n=lrd(),k=lrd();
    for(int i=1;i<=n;i++){
        a[i].num=lrd();
        a[i].id=1ll*i;
    }
    sort(a+1,a+1+n,cmp);
    vector<LL> v;
    LL ans=1,co=0;
    for(int i=1;i<=k;i++){
        co+=a[i].num;
        v.push_back(a[i].id);
    }
    sort(v.begin(),v.end());
    for(int i=0;i<k-1;i++)
        ans=(ans*(v[i+1]-v[i]))%MOD;
    cout<<co<<" "<<ans<<endl;
    return 0;
}

你可能感兴趣的:(数据结构,垃圾分类,#,马拉车)