【CodeForces训练记录】Codeforces Round 1043 (Div. 3)

赛后反思

继上次蓝桥杯国赛这次又被数位DP创飞了

训练情况

image

A题

简单模拟,D加在字符串后面,V加在字符串前面

点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'

using namespace std;

void solve(){
    int n; cin>>n;
    string s; cin>>s;
    int m; cin>>m;
    string t; cin>>t;
    string tt; cin>>tt;
    for(int i = 1;i<=m;i++){
        if(tt[i-1] == 'D') s = s + t[i-1];
        else if(tt[i-1] == 'V') s = t[i-1] + s;
    }
    cout<<s<<endl;
}

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

B题

我们考虑给出的 \(n\) 表达为这个形式 \(10^i \times x + x\),显然我们可以将 \(x\) 提取公因数出来变成 \(x \times (10^i + 1)\),所以我们直接枚举 \(10^i + 1\),即可。

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'

using namespace std;

void solve(){
    int n; cin>>n;
    set<int> ans;
    int c = 1;
    for(int i = 18;i;i--){
        c *= 10;
        if(n%(c+1)==0) ans.insert(n/(c+1));
    }
    cout<<ans.size()<<endl;
    for(auto i:ans) cout<<i<<" ";
    if(ans.size()) cout<<endl;
}

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

C1题

由观察得想要交易次数最少显然要取最大的 \(3^i\),所以我们贪心无脑取最大的减即可(可以等效为转三进制)

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'

using namespace std;

int qpow(int a,int b){
    if(b<0) return 0;
    int x = a;
    int y = b;
    int ans = 1;
    while(y){
        if(y&1){
            ans *= x;
        }
        x *= x;
        y >>= 1;
    }
    return ans;
}

void solve(){
    int n; cin>>n;
    int ans = 0;
    while(n){
        // cout<<n<<endl;
        for(int i = 20;~i;i--){
            int a = qpow(3,i);
            if(a<=n){
                n-=a;
                ans += qpow(3,i+1) + i * qpow(3,i-1);
                break;
            }
        }
    }
    cout<<ans<<endl;
}

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

C2题

我们可以计算一下单个西瓜的价格为 \(3 + \frac{x}{3}\),是一次函数,我们首先不考虑 \(k\) 的限制因素,如果想要花的硬币最少当然全部选择 \(3^0\) 个西瓜买,这样单价是最便宜的,接下来考虑有 \(k\) 的限制,如果我们无脑取 \(3^0\) 次数显然会超出 \(k\),我们先考虑次数最少(即转三进制的情况),此时的次数对应三进制数位和,如果这个都不满足则答案为 \(-1\),这时数位和距离 \(k\) 还有余量,因为越靠近 \(3^0\) 单价越小,接下来我们可以做一个从高位到低位的三进制退位的操作,高位的退位操作一定比低位的操作更优,因为是一次函数,直到这个余量耗光为止。

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'

using namespace std;

int qpow(int a,int b){
    if(b<0) return 0;
    int x = a;
    int y = b;
    int ans = 1;
    while(y){
        if(y&1){
            ans *= x;
        }
        x *= x;
        y >>= 1;
    }
    return ans;
}

void solve(){
    int n,k; cin>>n>>k;
    vector<int> s;
    while(n) s.emplace_back(n%3),n/=3;
    int sum = 0;
    for(auto i:s) sum += i;
    if(sum > k){
        cout<<-1<<endl;
        return;
    }
    sum = k - sum;
    for(int i = s.size()-1;i;i--){
        if(!sum) break;
        if(!s[i]) continue;
        int d = min(sum/2,s[i]);
        if(sum - 2*d >= 0){
            sum -= 2*d;
            s[i] -= d;
            s[i-1] += 3 * d;
        }
    }
    int ans = 0;
    int tot = 0;
    // for(auto i:s) cout<<i<<" "; cout<<endl;
    for(auto i:s) ans += i * (qpow(3,tot+1) + tot * qpow(3,tot-1)),tot++;
    cout<<ans<<endl;
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
    int T; cin>>T; while(T--)
    solve();
    return 0;
}
posted @ 2025-08-22 01:03  MNNUACM_2024ZY  阅读(60)  评论(0)    收藏  举报