Codeforces Round #506 (Div. 3) 题解

Codeforces Round #506 (Div. 3)

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

A. Many Equal Substrings

题意:

给出长度为n的字符串,然后要求你添加一些字符,使得有k个这样的字符串。

题解:

直接暴力吧...一个指针从1开始,另一个从2开始,逐一比较看是否相同;如果不同,第一个指针继续回到1,第二个指针从3开始...就这么一直重复。最后如果第二个指针能够顺利到最后一位,那么记录当前的第一个指针,把他后面的串取出来添加k-1个就ok了。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 55;
string s;
int n,k;
int main(){
    cin>>n>>k;
    cin>>s;
    int fir = 0,last = 1;
    for(int i=1;i<n;i++){
        if(s[fir]==s[i]) fir++;
        else if(fir) fir = 0,i=last+1,last=i;
    }
    string tmp = s.substr(fir,n);
    for(int i=1;i<k;i++) s+=tmp;
    cout<<s;
    return 0;
}
View Code

 

B. Creating the Contest

题意:

给出n个数,选出最长的区间,满足区间中的相邻两个数a,b有2*a>=b且a<b。

题解:

枚举+判断一下就ok了。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll ;
const int N = 2e5+5;
ll a[N];
int n;
int main(){
    scanf("%d",&n);
    int l=1,r=1,ans=1;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=2;i<=n;i++){
        if(a[i]<=a[i-1]*2){
            r++;
            ans=max(ans,r-l+1);
        }else{
            l=r=i;
        }
    }
    cout<<ans;
    return 0;
}
View Code

 

C. Maximal Intersection

题意:

给出n个区间,然后你可以任意去掉一个区间,最后求区间交集的最大值为多少。

题解:

区间的交集就是[maxl,minr]...根据这个求出前缀、后缀的l和r,然后枚举去掉哪个区间就行了。注意一下这里区间的交集是所有区间的交集。

代码如下:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 3e5+5;
int n;
struct line{
    int l,r;
}p[N];
int prel[N],prer[N],sufl[N],sufr[N];
int main(){
    scanf("%d",&n);
    memset(prer,INF,sizeof(prer));
    memset(sufr,INF,sizeof(sufr));
    for(int i=1;i<=n;i++) scanf("%d%d",&p[i].l,&p[i].r);
    for(int i=1;i<=n;i++){
        prel[i]=max(prel[i-1],p[i].l);
        prer[i]=min(prer[i-1],p[i].r);
    }
    for(int i=n;i>=1;i--){
        sufl[i]=max(sufl[i+1],p[i].l);
        sufr[i]=min(sufr[i+1],p[i].r);
    }
    int ans = 0;
    for(int i=1;i<=n;i++){
        int l = max(prel[i-1],sufl[i+1]);
        int r = min(prer[i-1],sufr[i+1]);
        ans=max(ans,r-l);
    }
    printf("%d",ans);
    return 0;
}
View Code

 

D. Concatenated Multiples

题意:

给出n个数以及k,现在将任意两个数聚合成为一对,比如12和345聚合就为12345,问一共有多少对能被k整除。

题解:

将a,b聚合,聚合之后的数即位a*10^len(b)+b,如果满足(a*10^len(b)+b%k)==0,则有a*10^len(b)%k+b%k=k or 0。

根据这个来写就好了,最后时间复杂度为O(10*nlogn)。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+5;
ll n,k;
ll a[N],b[N],len[N],q[12];
vector <ll> vec[12];
int main(){
    scanf("%I64d%I64d",&n,&k);
    q[0]=1;
    for(int i=1;i<=10;i++) q[i]=q[i-1]*10%k;
    for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++) b[i]=a[i];
    for(int i=1;i<=n;i++){
        ll x=a[i];
        int cnt=0;
        while(x){
            x/=10;
            cnt++;
        }
        len[i]=cnt;
    }
    for(int i=1;i<=10;i++){
        for(int j=1;j<=n;j++)
            vec[i].push_back(a[j]*q[i]%k);
        sort(vec[i].begin(),vec[i].end());
    }
    ll ans = 0;
    for(int i=1;i<=n;i++){
        b[i]%=k;
        int l = len[i];
        int pos1 = lower_bound(vec[l].begin(),vec[l].end(),(k-b[i])%k)-vec[l].begin();
        int pos2 = upper_bound(vec[l].begin(),vec[l].end(),(k-b[i])%k)-vec[l].begin();
        ans+=(pos2-pos1);
        if(a[i]*q[l]%k==(k-b[i])%k)ans--;
    }
    printf("%I64d",ans);
    return 0;
}
View Code

 

 

F. Multicolored Markers

题意:

给出a和b,代表两种颜色的格子数目。现在用他们围成一个矩形,还要要求至少有一种颜色围成一个矩形。现在求最短周长为多少。

题解:

用sqrt(a+b)的时间复杂度可以求出大矩形的因子有哪些。然后枚举每个因子,再来判断一下a or b是否能在我们枚举出来的长以及宽内围成一个矩形就行了。

我的做法时间复杂度比较高,说一个时间复杂度比较低的解法吧。

就是假定我们现在来判断a是否能围成矩形,那么我们要用sqrt(a)的时间复杂度来求出所有的因子,我们把宽度从小到大来存。对于大矩形也是这样。然后如果大矩形确定了长l,宽w,那么小矩形我们就贪心得选择最大的宽w'同时满足w'<=w,那么此时l'就是最小,然后判断一下此时是否l'<=l就行了。

之后就继续增大w,重复上面的操作...最后维护一下答案就行了。

我的暴力代码..

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,c;
vector <ll> v1,v2,v3;
bool check(ll l,ll s){
    ll r=s/l;
    for(auto width:v2){
        ll len = c/width;
        if(width<=l && len<=r) return true;
    }
    return false;
}
int main(){
    cin>>a>>b;
    ll s=a+b;
    c=a;
    for(ll i=1;i*i<=s;i++)
        if(s%i==0) v1.push_back(i);
    for(ll i=1;i*i<=c;i++)
        if(c%i==0) v2.push_back(i);
    ll ans;
    for(int i=v1.size()-1;i>=0;i--){
        ll l=v1[i],r=s/v1[i];
        if(check(l,s)){
            ans = (v1[i]+s/v1[i])*2;
            break ;
        }
    }
    c=b;v2.clear();
    for(ll i=1;i*i<=c;i++)
        if(c%i==0) v2.push_back(i);
    for(int i=v1.size()-1;i>=0;i--){
        ll l=v1[i],r=s/v1[i];
        if(check(l,s)){
            ans = min((v1[i]+s/v1[i])*2,ans);
            break ;
        }
    }
    printf("%I64d",ans);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/heyuhhh/p/10294095.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值