题解 P6101【出言不逊】

我知道了,但你出言不逊是!

这题嘛(ldotsldots) 比赛时瞎打一通,结果真过了。

下面是正题:首先,来审题。注意只是出现,并不一定是连续出现,我在比赛一开始时没仔细看,在加上样例也有误导性,就将简单问题复杂化了。每次操作后,可增加的字符数量就会翻倍。

弄清楚题目后,就会发现其实这题就是一个再简单不过的贪心。稍微进行简单的分析,也就可以知道:在读入字符串的时候,找出出现次数最多的字符,然后一直对它出言不逊进行如题所说的操作,所需的步数就是最小的了。

cin>>s>>l;
for(register int i=0;i<s.length();++i)
{
	++a[s[i]-'0'];         //相当于用字符作下标。 
	if(a[s[i]-'0']>hsy)         //当此字符数量更多时,就更新答案。 
	{
		hsy=a[s[i]-'0'];
	}
}

至于操作过程,先用一个变量存储 (|S|)(L) 的差,然后进入一个死循环,在循环内判断。如果所增加的字符数大于等于 此变量,就输出,然后跳出循环;否则,将此变量减去所增加的字符,然后将每次字符增加的量乘上 (2),继续循环(ldotsldots)总有一天会达到的。

l-=s.length();   //求出梦想和现实的差距。 
while(1)
{
	if(hsy>=l)      //如果可以出言不逊了,就输出。 
	{
		cout<<ans<<endl;
		return 0;
	}
	l-=hsy;    //否则,差距减去增加的部分。 
	hsy*=2;    //每次增加的数量要乘以 2。 
	++ans;
}

这样做的好处就是可以避免在 (nleq2^{64}) 这种毒瘤数据下会爆 usigned long long 的可能,毕竟打一个高精度是很烦的。

但它的坏处就是,在 (|S|geq L) 时,就会出错,所以要进行一次特判。

if(s.length()>=l)     //此时不用变化。 
{
	cout<<0;       
	return 0;
}

交上去,就能愉快地 AC 了。


泥萌最喜欢的完整 AC 代码:

#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
string s;
ull l,a[101],hsy,ans=1;
int main()
{
	cin>>s>>l;
	if(s.length()>=l)     
	{
		cout<<0;       
		return 0;
	}
	for(register int i=0;i<s.length();++i)
	{
		++a[s[i]-'0'];        
		if(a[s[i]-'0']>hsy)      
		{
			hsy=a[s[i]-'0'];
		}
	}
	l-=s.length();  
	while(1)
	{
		if(hsy>=l)      
		{
			cout<<ans<<endl;
			return 0;
		}
		l-=hsy;   
		hsy*=2;    
		++ans;
	}
	return 0;	
}

我知道,肯定有很多大佬的程序能吊打我,但是体谅一下一个小蒟蒻吧。

原文地址:https://www.cnblogs.com/win10crz/p/12859662.html