Codeforces Round 921 (Div. 2)(A~B)

A. We Got Everything Covered!

找出一个字符串S,满足条件:所有可能的长度为n,使用前k个小写字母的字符串P都是S的子串。

其中字符串S的长度尽可能短。

这种构造题,构造S的时候尽可能在原有的基础上去扩展,如果能扩展出来,那就是有规律。

n=1,k=3

S:abc

n=1,k=4(+1)                n=2(+1),k=3

S:abcd                             S:abcabc

n决定了每个字母最少出现的次数,所以上面的答案均是最短的情况。

AC代码

#include <bits/stdc++.h>
//#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;

int n,k;

void solve(){
    cin>>n>>k;
    per(i,1,n){
        per(j,1,k){
            cout<<(char)('a'+j-1);
        }
    }
    cout<<endl;
}

void init(){

}
signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr);
    int t;
    cin>>t;
    while(t--)solve(),init();
    return 0;
}

补题:B. A Balanced Problemset?

题意:给你一个数N,拆数拆成X个,计算他们的gcd值为P,在所有拆数的情况里面,输出最大的P值。

思路:最大的P值,即这些被拆开数的最大公约数,既然是公共的约数,那么被拆出来的数一定是有倍数关系的,比如:2 2 4 8(均为2的倍数),3 3 3 3 6(均为3的倍数)。

那显然最好的情况是数N,被拆成X个数后,设N/X=k,如果没有余数p全都相等,那k就是答案。

不可能找出最大的公约数k+1,不然数每个数都要增大一,数N就要变成N+k了。

如果拆出来有余数,那就分两种情况:

1. 余数 p 是 k 的倍数,那 k 就是答案(答案不可能是k+1,余数是小于X的,不可能均摊让所有数+1)

2. 余数 p 不是 k 的倍数,那我们只能考虑更小的答案,即 k--,p+=n(一共有n份数,每份都减一),直到 p 成为 k 的倍数。

#include <bits/stdc++.h>
//#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;

int x,n;

void solve(){
    cin>>x>>n;
    int k=x/n;//均分,每份为k
    if(k*n==x){//没有余数
        cout<<k<<endl;
        return;
    }else{//有余数,设为p
        int p=x-(k*n);
        if(p%k==0){//余数是倍数部分
            cout<<k<<endl;
            return;
        }else{//余数不是倍数
            //如果不是那就把整体全部缩水1
            while(p%k!=0){//找到成为倍数为止
                p+=n;
                k--;
            }
            cout<<k<<endl;
            return;
        }
    }
}

void init(){

}
signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr);
    int t;
    cin>>t;
    while(t--)solve(),init();
    return 0;
}

这个代码的复杂度可以看出来是k*T,最差情况下k=1e8,T=1e3,总计1e11的复杂度,这道题大概率是过不了的。

T我们没法改变,那就尝试优化一下内部的k。

拆出来的数为 k k k k k,p,只有当余数p是k的倍数的时候,也可以没有余数才能成为答案,因此拆出来的就是一堆k,显然k是总数x的因子,也就是把因子都跑一遍就行了。

#include <bits/stdc++.h>
#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;

int x,n,ans;

void solve(){
    cin>>x>>n;
    per(i,1,sqrt(x)){
        if(x%i==0){
            int tmp=x-n*i;//此处tmp就是p
            if(tmp>=0 and tmp%i==0)ans=max(ans,i);//是否可以形成 k k k k k,p的情况
            tmp=x-n*(x/i);
            if(tmp>=0 and tmp%(x/i)==0)ans=max(ans,x/i);//判断右半边的因数
        }
    }
    cout<<ans<<endl;
}

void init(){
    ans=-1;
}
signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr);
    int t;
    cin>>t;
    while(t--)solve(),init();
    return 0;
}
相关知识点:

设x*x=P,P的因数分为两个区域 [1~x] 和 [x~P]

其中左边的因数会对应右边区间的因数,并且是完全对应。

若左半边因数为i,那么右半边对应的就是P/i

所以找出一个数P的因数只需要判断1~sqrt(P)里面的因数就可以了,剩下的右半边除出来

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值