目录
知识点:贪心,模拟
题意
给定 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;
}