Time Limit:2s Memory Limit:64MByte
Submissions:271Solved:50
Eris has a string s=s1s2...sns=s1s2...sn. Let xx and yy be two characters in ss, f(x,y)f(x,y) be the difference between the number of occurrences of xx in ss and the number of occurrences of yy in ss and B(s)B(s) be the maximum value of f(x,y)f(x,y) (i.e. B(s)=maxx,y∈sf(x,y)B(s)=maxx,y∈sf(x,y)).
Eric wants to remove at most mm characters of ss to make B(s)B(s) as small as possible.
题目大意:
我们可以最多删除m个字符,使得每个字符出现的次数中最大值和最小值的绝对值差尽可能的小,问最小是多少。
思路:
1、首先我们统计每个字符出现的次数,然后对其进行排序。
2、一开始觉得对排序之后的序列,让最大值尽可能的小就能够得到正解了,其实不然,一些情况需要我们对最小值进行增大才行,所以我们只单单考虑最大值减小是不够的。
那么我们考虑枚举最大值和最小值。
此时我们可以枚举一个最小值,然后去二分最大值,将不在最小值和最大值之内的字符全部删除即可。
过程维护需要进行的删除个数,如果总共需要删除的个数小于等于m个,那么对应我们可以继续减小最大值,否则增大最大值。
过程维护最小差值即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
int vis[500];
int b[100050];
char a[100050];
int n,m;
int cnt;
int Slove(int mid,int di)
{
int need=0;
for(int i=0;i<cnt;i++)
{
if(b[i]>mid)
{
need+=b[i]-mid;
}
else if(b[i]<di)need+=b[i];
}
if(need<=m)return 1;
else return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
cnt=0;
memset(vis,0,sizeof(vis));
scanf("%d%d",&n,&m);
scanf("%s",a);
for(int i=0;i<n;i++)
{
vis[a[i]]++;
}
for(int i=0;i<n;i++)
{
if(vis[a[i]]>0)
{
b[cnt++]=vis[a[i]];
vis[a[i]]=0;
}
}
sort(b,b+cnt);
int output=0x3f3f3f3f;
for(int i=0;i<cnt;i++)
{
int l=b[i];
int r=b[cnt-1];
int ans=-1;
while(r-l>=0)
{
int mid=(l+r)/2;
if(Slove(mid,b[i])==1)
{
r=mid-1;
ans=mid-b[i];
}
else l=mid+1;
}
if(ans==-1)continue;
output=min(output,ans);
}
printf("%d\n",output);
}
}