题解:P12835 [蓝桥杯 2025 国 B] 蓝桥星数字
vegetableYe · · 题解
第十六届蓝桥杯CB国赛 F-蓝桥星数字
当
(我猜可能甚至
(蓝桥杯并不是第一次干这种事情了)
模拟代码:
bool good(int x) {
string s = to_string(x);
bool f = (s[0] - '0') & 1;
for(int i = 1; i < s.size(); i++) {
int u = (s[i] - '0') & 1;
if(f ^ u) {
f ^= 1;
} else {
return 0;
}
}
return 1;
}
int ans = 0;
for(int i = 10; ; i++) {
if(good(i)) {
ans++;
}
if(ans == x) {
ans = i;
break;
}
}
cout << ans << endl;
正解(前置知识:数位 dp 。)
本题应该是有很智慧的递推做法的,但笔者在赛场上没想到,于是想到了一个无脑但稳对的做法。
像这种:求第
二分答案+数位
我们二分答案,假设题目求的第
而数位
因此我们的
最后需要注意的是,二分的下界要设为
笔者赛时的代码:
int x;
string s;
int dp[22][2][3];
int dfs(int u, int lst, int cnt, bool limit, bool lead0) {
if(u == s.size()) {
if(!lead0 && cnt > 1) {
return 1;
}
return 0;
}
if(!lead0 && !limit && dp[u][lst][cnt] != -1) {
return dp[u][lst][cnt];
}
int ans = 0;
int up = (limit ? s[u] - '0' : 9);
for(int i = 0; i <= up; i++) {
int now = i & 1;
if(lst == -1 || (now ^ lst)) {
if(lead0 && (i == 0)) {
ans += dfs(u + 1, -1, cnt, limit & (i == up), 1);
} else {
ans += dfs(u + 1, now, min(2LL, cnt + 1), limit & (i == up), lead0 & (i == 0));
}
}
}
return dp[u][lst][cnt] = ans;
}
bool check(int r) {
s = to_string(r);
memset(dp, -1, sizeof dp);
return dfs(0, -1, 0, 1, 1) >= x;
}
void solve() {
cin >> x;
int l = 10, r = 4e18; // r 可以调整为 10^18,赛时的笔者稳妥起见直接取到能取的最大值了
while(l < r) {
int mid = (l + r) / 2;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
}
时间复杂度: