Educational CF Round 116 (Rated for Div. 2) C Banknotes
知识点:贪心,模拟
题意
给定 k k k, b i b_i bi为长度为 n n n且元素为自然数的任意数组,且满足元素之和小于等于k。求 M E X ( { x ∣ x = ∑ i = 1 n 1 0 a i × b i } ) MEX(\{x|x=\sum _{i=1}^n10^{a_i}\times b_i\}) MEX({ x∣x=∑i=1n10ai×bi})
思路
不存在选 a i a_i ai大的方案比 a i a_i ai小的方案MEX还小(证明大的方案下MEX在小的方案下存在)。可以贪心维护选 a i a_i ai越小越好,直到可以由次小的维护,即设 c c c为选 a i a_i ai的个数,当 a i × c = a i + 1 a_i\times c=a_{i+1} ai×c=ai+1时, a i + 1 a_{i+1} ai+1代替 a i × c a_i\times c ai×c, a i a_i ai取 c − 1 c-1 c−1保证贪心。
考虑到假设 k = c − 1 k=c-1 k=c−1时选 k k k个 a i a_i ai,贪心地令MEX为选 k + 1 k+1 k+1个 a i a_i ai时的结果,会导致 k = c k=c k=c发生上述代替(说明令的MEX是错的),所以 k = c − 1 k=c-1 k=c−1时就要取次小的。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=100;
ll n,k;
ll arr[N];
ll ten[N];//预处理10的i次方
void init()
{
ten[0]=1;
for(ll i=1; i<20; i++)
ten[i]=ten[i-1]*10;
}
void solve()
{
scanf("%lld%lld",&n,&k);
for(ll i=1; i<=n; i++) scanf("%lld",&arr[i]);
ll ans=0;
for(ll i=1; i<=n-1; i++)
{
ll c=ten[arr[i+1]-arr[i]];//次小除小为思路中的c
if(k>=c-1)//保存a[i]的取法,下一步取a[i+1]
{
ans+=ten[arr[i]]*(c-1);//取c-1个a[i]
k-=c-1;
}
else//再也无法用次小的替换了
{
ans+=ten[arr[i]]*(k+1);//k<=c-2,保证MEX取k个a[i]时k<=c-1或k<c(无法替换)
printf("%lld\n",ans);
return ;
}
}
//特判a[n]没有比它更大的a[n+1]了。
printf("%lld\n",ans+ten[arr[n]]*(k+1));//没有c的限制(或者说c=inf)
}
int main()
{
ll t;
scanf("%lld",&t);
init();
while(t--)
solve();
return 0;
}