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({xx=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 c1保证贪心。
考虑到假设 k = c − 1 k=c-1 k=c1时选 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=c1时就要取次小的。

代码

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值