【CodeForces训练记录】Codeforces Round 1043 (Div. 3)
赛后反思
继上次蓝桥杯国赛这次又被数位DP创飞了
训练情况

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;
}

浙公网安备 33010602011771号