Codeforces Round #739 (Div. 3)


D. Make a Power of Two

题意:
给一个数 n n n,可以删除某一位或在后面添加任意一个数,求把 n n n变为二的幂次最少需要多少步

思路:枚举+双指针
暴力枚举 n n n x = 2 0 ∼ 2 62 x=2^0\sim 2^{62} x=20262需要几步,统计 n n n的子序列能最多匹配 x x x的前缀的长度 l e n len len
步数为 ∣ n ∣ − l e n + ∣ x ∣ − l e n |n|-len+|x|-len nlen+xlen ∣ n ∣ − l e n |n|-len nlen表示要变成 x x x的前缀需要删掉几个数, ∣ x ∣ − l e n |x|-len xlen表示要添加前缀后面的数

AC代码:

#include <string>
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i ++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define MST(a,x) memset(a,x,sizeof(a))
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()
#define ll long long
#define int ll
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ls u<<1
#define rs u<<1|1
typedef pair<int,int> PII;
typedef vector<int> VI;
const int MAXN=100;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;

string s[MAXN];

int get(string t,string s){
    int i=0,j=0;
    while(i<SZ(t)){
        if(t[i]==s[j]) i++,j++;
        else i++;
        if(j==SZ(s)) break;
    }
    return SZ(t)+SZ(s)-2*j;
}

void solve(){
    string t;
    cin>>t;
    int ans=2e9;
    rep(i,0,62){
        ans=min(ans,get(t,s[i]));
    }
    cout<<ans<<endl;
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int x=1;
    s[0]="1";
    rep(i,1,62){
        x*=2;
        s[i]=to_string(x);
    }
    int t;cin>>t;while(t--)
    solve();
    return 0;
}

E. Polycarp and String Transformation

题意:
有两个字符串 s , t s,t s,t和一个给定顺序 o r d e r order order,最初 t = s t=s t=s,然后每次把 s s s里所有的 o r d e r i order_i orderi删除加到 t t t里去,现在给你 t t t,输出 s s s o r d e r order order

思路:模拟+思维
由于删除顺序,所以每个字符的最后的出现位置即为 o r d e r order order t t t中出现的字符数一定是 s s s出现次数的倍数,用 c n t cnt cnt表示每个字符出现的次数, o r d e r i order_i orderi对应字符在 s s s中的次数为 c n t o r d e r i i + 1   0 ≤ i < ∣ o r d e r ∣ \frac{cnt_{order_i}}{i+1}\space 0\le i< |order| i+1cntorderi 0i<order,因此 s s s中的总字符数为 ∑ i = 0 ∣ o r d e r ∣ − 1 c n t o r d e r i i + 1 \sum_{i=0}^{|order|-1} \frac{cnt_{order_i}}{i+1} i=0order1i+1cntorderi,再根据题意模拟是否等于 t t t,否则输出 − 1 -1 1

AC代码:

#include <iostream>
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i ++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define MST(a,x) memset(a,x,sizeof(a))
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()
#define ll long long
#define int ll
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ls u<<1
#define rs u<<1|1
typedef pair<int,int> PII;
typedef vector<int> VI;
const int MAXN=1;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;

string t,order="";
map<char,int> vis,cnt;

bool check(string s){
    string res;
    rep(i,0,SZ(order)-1){
        res+=s;
        s.erase(remove(s.begin(),s.end(),order[i]),s.end());
    }
    return res==t;
}

void solve(){
    cin>>t;
    order="";
    
    int n=SZ(t),len=0;
    vis.clear();
    cnt.clear();
    
    per(i,n-1,0){
        if(!vis[t[i]]){
            order=t[i]+order;
            vis[t[i]]=1;
        }
        cnt[t[i]]++;
    }
    
    int res=0;
    rep(i,0,SZ(order)-1) res+=cnt[order[i]]/(i+1);
    // cout<<res<<endl;

    string s1="";
    
    rep(i,0,res-1) s1+=t[i];

    if(check(s1)){
        cout<<s1<<" "<<order<<endl;
    }else cout<<"-1\n";
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int _;cin>>_;while(_--)
    solve();
    return 0;
}

F2. Nearest Beautiful Number (hard version)

题意:
给定两个数 n , k n,k n,k,找到 ≥ n \ge n n的最小的 x x x x x x中出现数的种类 ≤ k \le k k

思路:枚举+贪心
如果 n n n符合条件,直接输出 n n n,如果 k = 1 k=1 k=1,如果所有位全取第一个数合法则输出,否则把每一位加一,如果 k > 1 k>1 k>1从后往前枚举 n n n的每一位,枚举这位到 9 9 9的所有情况, c n t cnt cnt表示当前出现数的种数,如果 c n t = k cnt=k cnt=k,那么后面的位全取之前出现最小位,如果 c n t < k cnt<k cnt<k,后面的位可以全取 0 0 0

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define ll long long
#define int ll
#define pb push_back
#define mp make_pair
#define SZ(x) (int)(x.size())
#define ALL(x) (x).begin(),(x).end()
#define mst(a,x) memset(a,x,sizeof(a))
#define ls u<<1
#define rs u<<1|1
typedef vector<int> VI;
typedef pair<int,int> PII;
const int maxn=1e6+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;

int getcnt(string s)
{
    set<char> S;
    for(auto c:s) S.insert(c);
    return SZ(S);
}

void solve()
{
    string n;
    int k;
    cin>>n>>k;
    string res;
    int num=stoi(n);

    if(getcnt(n)<=k) cout<<n<<endl;
    else
    {
        if(k==1)
        {
            rep(i,1,SZ(n)) res+=n[0];
            if(stoi(res)>=num) cout<<res<<endl;
            else
            {
                for(auto &c:res) c++;
                cout<<res<<endl;
            }
        }
        else
        {
            int cnt=0,res=2e9;
            while(SZ(n))
            {
                while(n.back()<'9')
                {
                    n.back()++;
                    string cur=n;
                    int p=getcnt(n);
                    if(p<=k)
                    {
                        char minv='9';
                        for(auto t:n) minv=min(minv,t);
                        rep(i,1,cnt)
                        {
                            if(p==k) cur+=minv;
                            else cur+='0';
                        }
                        res=min(res,stoi(cur)*1ll);
                    }
                }
                n.pop_back();
                cnt++;
            }
            cout<<res<<endl;
        }
    }
}

signed main()
{
#ifdef LOCAL
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int _;cin>>_;while(_--)
    solve();
    return 0;    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值