bun
Description
因为体育老师很喜欢等差数列,所以他要求学生们站队必须按身高站成等差数列。
但是有些班级的学生无论如何也无法排成等差数列,于是体育老师从食堂买来了两种神
奇的面包。吃一个第一种面包可以使身高增 1,吃一个第二种面包可以使身高减 1。
你的任务是,对于某个班级,帮助老师安排哪些同学食用多少面包。考虑到学生的身体
健康,体育老师希望吃面包最多的学生吃的面包数量尽量少。
Input Format
第一行一个正整数 n,表示学生的数目。
第二行是长度为 n 的整数序列 a, a[i]表示第 i 个学生的身高。由于体育老师使用的奇怪
的身高单位,学生身高可能是负数。可以打乱顺序重新排列。
Output Format
第一行一个整数,表示吃面包最多的学生吃的面包数量。
第二行两个整数,分别表示等差数列的首项和公差,公差不能为负。
如果有多解,输出公差最小的方案。如果还有多解,输出首项最小的方案。
Sample Input (1)
5
-3 -4 -2 -3 3
Sample Output (1)
2
-3 1
Sample Input (2)
5
2 -3 -1 -4 3
第 8 页 共 8 页
Sample Output (2)
1
-4 2
Hint
对于 30%的数据,n<=100,a[i]的绝对值<=1000。
对于 60%的数据,n<=1000,a[i]的绝对值<=100000。
对于 100%的数据,n<=100000,a[i]的绝对值<=1000000。
<法一>记f1为当前需要吃的增高面包的最大的量,f2为当前需要吃的减低面包最大的量。
考虑暴力的情况,枚举公差d,我们可以通过计算f1、f2,再取中位数的方式得到当前的最优首项。
我们把每个d对应的f1、f2打出表来,就可以发现,f1单调递减,f2单调递增,它们两个相交的位置就是答案,二分即可(怕写错,写了分块答案)。
<法二>orz faebdc,我们在枚举d的时候,易发现,d最大不会超过4*max(a[i])/n,否则还不如把a全变0更优,因此暴力就好啦~
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define N 100001 int n,a[N],ans=2147483647,b[N],f1,f2,D,X0; int main() { scanf("%d",&n); if(n<=1000){ for(int i=1;i<=n;++i) scanf("%d",&a[i]); sort(a+1,a+n+1); int lim=30000000/n; f1=f2=0; for(int i=1;i<=n;++i) { b[i]=a[1]-a[i]; if(b[i]>0) f2=max(f2,b[i]); else f1=max(f1,-b[i]); } if(ans>((f1+f2+1)>>1)) { ans=((f1+f2+1)>>1); D=0; if(f1<f2) X0=a[1]-(((f1+f2+1)>>1)-f1); else X0=a[1]+(f1-((f1+f2+1)>>1)); } for(int d=1;d<=lim;++d) { f1=f2=0; for(int i=2;i<=n;++i) { b[i]+=(i-1); if(b[i]>0) f2=max(f2,b[i]); else f1=max(f1,-b[i]); } if(ans>((f1+f2+1)>>1)) { ans=((f1+f2+1)>>1); D=d; if(f1<f2) X0=a[1]-(((f1+f2+1)>>1)-f1); else X0=a[1]+(f1-((f1+f2+1)>>1)); } } printf("%d\n%d %d\n",ans,X0,D); return 0; } for(int i=1;i<=n;++i) scanf("%d",&a[i]); sort(a+1,a+n+1); f1=f2=0; for(int i=1;i<=n;++i) { b[i]=a[1]-a[i]; if(b[i]>0) f2=max(f2,b[i]); else f1=max(f1,-b[i]); } if(ans>((f1+f2+1)>>1)) { ans=((f1+f2+1)>>1); D=0; if(f1<f2) X0=a[1]-(((f1+f2+1)>>1)-f1); else X0=a[1]+(f1-((f1+f2+1)>>1)); } if(f2>=f1) { printf("%d\n%d %d\n",ans,X0,D); return 0; } int sz=sqrt(n),last=0; for(int i=1;last<=n;i+=sz) { f1=f2=0; for(int j=2;j<=n;++j) { b[j]+=(i==1?1:sz)*(j-1); if(b[j]>0) f2=max(f2,b[j]); else f1=max(f1,-b[j]); } if(ans>((f1+f2+1)>>1)) { ans=((f1+f2+1)>>1); D=i; if(f1<f2) X0=a[1]-(((f1+f2+1)>>1)-f1); else X0=a[1]+(f1-((f1+f2+1)>>1)); } if(f2>=f1) { for(int j=2;j<=n;++j) b[j]-=(i==1?1:sz)*(j-1); for(int j=last+1;j<=i;++j) { f1=f2=0; for(int k=2;k<=n;++k) { b[k]+=(k-1); if(b[k]>0) f2=max(f2,b[k]); else f1=max(f1,-b[k]); } if(ans>((f1+f2+1)>>1)) { ans=((f1+f2+1)>>1); D=j; if(f1<f2) X0=a[1]-(((f1+f2+1)>>1)-f1); else X0=a[1]+(f1-((f1+f2+1)>>1)); } if(f2>=f1) { printf("%d\n%d %d\n",ans,X0,D); return 0; } } } last=i; } return 0; }