Codeforces Round #506 (Div. 3)

Codeforces Round #506 (Div. 3)

题目链接:https://codeforces.com/contest/1029

 

A题题解

概述

 

    给定子字符串,构造包含k个该子字符串的最短字符串。

 

思路

 

    作为div 3的第一道题自然相当随意,数据量极小,O(k*n^3)也能过的样子,可以说有思路就没有问题,事实上我也看到有大佬迭代遍历AC这道题。

 

    不过当我初步推理这道题时,我马上联想到KMP算法。直觉告诉我这就是这道题的最优解法,而且可以利用现成代码。接下来我就讲一讲这道题关于KMP的解法~

 

    还不理解KMP算法的话...出门左转见度娘~

 

    首先想到,最傻的方法就是把k个t串起来,必然保证有k个t;

 

    如何使字符串长度更短?

 

    假设有某种办法,那么随着总长度缩短,必然造成相邻的子字符串相互重叠,但不会完全重合或存在包含关系。换句话说,我们只需要使子字符串之间重合部分最长,就得到了最短的目标字符串。

 

    而每个子字符串是相等的,也就是求子字符串自己头和尾的最长重合部分。

 

    例如子字符串t="abcab",“ab”就是t的最长重合部分。比如k=2时,s="abcabcab"。

 

    讲到这里熟悉KMP的朋友们就会发现,这正是KMP实现的核心思想,KMP初始化fail/next数组就保存着这样的信息。于是我们借用KMP的初始化函数,顿时这道题只剩下简单的处理。

 

    注意重合部分不能是子字符串本身,例如t="aaa"时最多只能重合"aa"。

#include<bits\stdc++.h> 
using namespace std; 
 
string r,s;
int fail[100]{0};
void make_fail(){
    for(int i=1,j=0;s[i];i++){
        while(j && s[i]!=s[j]) j=fail[j-1];
        if(s[i]==s[j])fail[i]=++j;
        else fail[i]=0;
    }
}
 
int main(){
    int n,k;
    cin>>n>>k;
    cin>>s;
    make_fail();
    int p=n-fail[n-1];
    if(p==0) p=1;
    for(int i=0;i<k-1;i++)
        r.append(s.substr(0,p));
    r.append(s);
    cout<<r;
    return 0;
}
View Code

运用substr来做

#include<stdio.h>
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,k;
    cin >> n >> k;
    string s;
    cin >> s;
    int temp;
for(int i = 0; i < n ; i++) if(s.substr(0,i) == s.substr(n-i,i))  temp = i;
for(int i = 0 ; i < k-1 ; i++) cout << s.substr(0,n-temp);
cout << s << endl;
return 0;
    
}
View Code

B题题解

https://blog.csdn.net/intmainhhh/article/details/82286299

#include<stdio.h>
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int a[200000+10];
int main(){
int n;
cin >> n;
int x = ~1+1;
//cout << x << endl;
int sum = 1;
for(int i = 0; i < n; i++){
    cin >> a[i];
    if(i > 0){
        if(a[i] <= a[i-1] * 2)
        sum++;
    
    else {
        x = max(sum,x);
        sum = 1;
    }
}
//    cout <<sum << endl;
}
//if(x==0)
//cout << "1" << endl;
//else
x = max(sum,x); 
cout << x << endl;
return 0;
View Code

C题题解

multiset弄一下;

https://www.cnblogs.com/Agnel-Cynthia/p/10604317.html

#include<bits/stdc++.h>
using namespace std;
int l[300005], r[300005];
multiset<int> a, b;
int main(){
    int n;
    cin >> n;
    for(int i = 0 ; i < n ; i++){
        cin >> l[i];
        cin >> r[i];
        a.insert(l[i]);
        b.insert(r[i]);
    }
    int ans = ~1 + 1 + 1;
    for(int i = 0 ; i < n; i ++){
        a.erase(a.find(l[i]));
        b.erase(b.find(r[i]));
        ans = max(ans,*b.begin() - *a.rbegin());
        a.insert(l[i]);
        b.insert(r[i]);
    }
    cout << ans << endl;
    return 0;
}
View Code

D题待补

 

E题待补

 

F题题解

数学题,就是已知两个颜色矩形的面积,要求最小周长,且满足其中一种颜色的为矩形

思路:面积相同,长越大周长越小。暴力遍历。

优化:

1.将宽从大到小遍历,如果满足,必然最小,直接输出

2.判断小矩形时,从大到小判断,减少复杂度(

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a ,b ,c ,d;
const ll inff = 0x3f3f3f3f3f3f3f3fLL; //18
bool check(ll x , ll y){
    
    for(ll i = x ; i >= 1 ; i-- ){
        if(a % i == 0 && a / i <= y) return 1;
        if(b % i == 0 && b / i <= y) return 1;
    }
    return false ;
}

int main(){
//ll a, b;
    cin >> a >> b;
     c = a + b;
     ll ans = inff;
     //从大往小枚举,即宽最大时,周长最小 
    for(ll i = 1ll; i * i <= c; i++){
        if(c % i == 0 ){
         d = c / i;
         if(check(i,d)){
             ans = min(ans,2ll * (d + i));
             //不优化反而更快 
         //    cout << ans << endl;
         //    return 0;
         }
        } 
    }
    cout << ans << endl;
}
View Code

 

posted @ 2019-03-27 01:11  Agnel_Cynthia  阅读(176)  评论(0编辑  收藏  举报
Live2D