CF1759F题解
Brief Description
给你一个 \(n\) 位的 \(p\) 进制数,第 \(i\) 位为 \(a_i\)。
请问最少要让该数加多少次 \(1\),可以让数码 \(0,\cdots,p−1\) 都出现过(包含在中间过程出现)。
Solution
因为是 \(p\) 进制,不难发现答案一定不会超过 \(p−1\),也就是说在最坏情况下就是其最后一位加至多 \(p−1\) 次才可以使得 \(0, \cdots ,p-1\) 每一个数码都出现一次。
然而题目给的数有 \(n\) 位,是有一定量的数码是出现过的。
所以显然可以考虑分进位与不进位分类讨论。
进位的条件其实就是存在小于它的数且它没有出现过。
这样讨论完了之后假设第一位为 \(x\) 那么小于等于 \(x\) 的都出现过,那么我们只需要找到一个最大的且没有出现过的数让 \(x\) 加到这个数就好了。
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 5e6+5;
int a[N];
map<int,bool> vis;
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,p;
scanf("%d%d",&n,&p);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
for(int i=1; i<=n; i++) vis[a[i]] = true;
reverse(a+1,a+n+1);
bool flag = true;
for(int i=a[1]; i>=max(a[1]-300,0); i--)
if(!vis[i])
flag = false;
set<int> st;
int ans = 0;
int limit = p - 1;
if(!flag){
ans += p - 1 - a[1] + 1;
limit = a[1] - 1;a[1] = 0;
a[2]++;
for(int i=2; i<=n; i++){
if(a[i] == p) a[i] = 0,a[i+1]++;
}
}
for(int i=1; i<=n; i++) vis[a[i]] = true;
if(a[n+1]) vis[a[n+1]] = true;
for(int i=limit; i>=max(limit-300,0); i--){
if(!vis[i]){
ans = ans + i - a[1];
break;
}
}
printf("%d\n",ans);vis.clear();
for(int i=1; i<=n+1; i++) a[i] = 0;
}
return 0;
}
本文来自博客园,作者:{_NightFire666_(洛谷uid 752555,欢迎关注)},转载请注明原文链接:https://www.cnblogs.com/NightFire666-blog/p/18665439

浙公网安备 33010602011771号