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=1n​10ai​×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;
}
上一篇:android:imeOptions属性(转)


下一篇:android:imeOptions属性