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;              
}
posted @ 2025-01-11 11:57  夜·煞  阅读(25)  评论(0)    收藏  举报