Codeforces Round #143 (Div. 二) C. To Add or Not to Add 胡搞
Codeforces Round #143 (Div. 2) C. To Add or Not to Add 胡搞
题意:给你一个数列(好吧,又是数列= =),可对这个数列中的某些数加一个值,但加的总值不能超过k。求在这些操作下,使得数列中的某个数出现的次数最多。
这个题纯靠yy,我们可以依次从数列中最小的数开始枚举,但复杂度为O(n^2),铁定超时。但是可以优化之,大大降低复杂度。首先对数列排序,然后依次从左往右开始枚举,那么这里可以有一个状态转移:假设当前状态还剩余d可操作,满足数相等的最左端的数的位置为l,那么新加一个数num[i+1],只要比较(num[i+1]-num[i])*(i-l+1)与d的关系即可,来改变l的位置,那么就能很快求出下一状态。
My code:
//STATUS:C++_AC_78MS_400KB #include<stdio.h> #include<stdlib.h> #include<string.h> #include<algorithm> #include<string> #include<vector> #include<queue> #include<stack> #include<set> #define LL __int64 #define Max(x,y) ((x)>(y)?(x):(y)) #define Min(x,y) ((x)<(y)?(x):(y)) #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define mem(a,b) memset(a,b,sizeof(a)) const int MAX=100010,INF=200000000,MOD=1000000007; const double esp=1e-6; int cmp(const void *a,const void *b){ return *(int*)a - *(int*)b; } int num[MAX]; int n; LL k; int main() { // freopen("in.txt","r",stdin); int i,j,l,max_cou,max_num; LL d; while(~scanf("%d%I64d",&n,&k)) { for(i=1;i<=n;i++) scanf("%d",&num[i]); qsort(num+1,n,sizeof(int),cmp); l=1; max_cou=1,max_num=num[1]; for(i=2;i<=n;i++){ d=(LL)(i-l)*(LL)(num[i]-num[i-1]); k-=d; while(k>0 && l>1 && num[i]-num[l-1]>=k){ l--; k-=num[i]-num[l]; } while(k<0 && l<i){ k+=num[i]-num[l]; l++; } if(i-l+1>max_cou){ max_cou=i-l+1; max_num=num[i]; } } printf("%d %d\n",max_cou,max_num); } return 0; }