BZOJ5090: [Lydsy1711月赛]组题(01分数规划)
5090: [Lydsy1711月赛]组题
Time Limit: 1 Sec Memory Limit: 256 MBSubmit: 785 Solved: 186
[Submit][Status][Discuss]
Description
著名出题人小Q的备忘录上共有n道可以出的题目,按照顺序依次编号为1到n,其中第i道题目的难度系数被小Q估计
为a_i,难度系数越高,题目越难,负数表示这道题目非常简单。小Q现在要出一套难题,他决定从备忘录中选取编
号连续的若干道题目,使得平均难度系数最高。当然,小Q不能做得太过分,一套题目必须至少包含k道题目,因此
他不能通过直接选取难度系数最高的那道题目来组成一套题。请写一个程序,帮助小Q挑选平均难度系数最高的题
目。
Input
第一行包含两个整数n,k(1<=n<=100000,1<=k<=n),分别表示题目的总量和题数的下界。
第二行包含n个整数a_1,a_2,...,a_n(|a_i|<=10^8),分别表示每道题目的难度系数。
Output
输出一个既约分数p/q或-p/q,即平均难度系数的最大值。
Sample Input
5 3
1 4 -2 -3 6
1 4 -2 -3 6
Sample Output
5/4
HINT
Source
思路:01分数规划,二分平均值,然后就是求最大的连续的长度不小于K的值,然后由于是需要输出分子分母形式,我们在二分的同时记录“和”与“长度”,最后约分输出即可。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) #define ll long long using namespace std; const int maxn=100010; int a[maxn],N,K; double b[maxn]; ll A,B,sum[maxn]; bool check(double Mid) { rep(i,1,N) b[i]=b[i-1]+a[i]-Mid; int pos=0; rep(i,K,N) { if(b[i]-b[pos]>=0){ A=sum[i]-sum[pos]; B=i-pos; return true; } if(b[i-K+1]<b[pos]) pos=i-K+1; }return false; } int main() { scanf("%d%d",&N,&K); double L=-100000000,R=100000000,Mid; int num=40; rep(i,1,N) scanf("%d",&a[i]),; rep(i,1,N) sum[i]=sum[i-1]+a[i]; while(num--){ Mid=(L+R)/2; if(check(Mid)) L=Mid; else R=Mid; } if(A<0) putchar('-'),A=abs(A); ll g=__gcd(A,B); printf("%lld/%lld\n",A/g,B/g); return 0; }
但是不知道为什么我自己的check函数是WA的,难道是delta一直做加减法引起的精度问题?
bool check(double Mid) { rep(i,1,N) b[i]=(double)a[i]-Mid; int head=1; double delta=0; rep(i,1,N) { delta+=b[i]; while(i-head+1>K&&b[head]<0) delta-=b[head++]; if(i-head+1>=K&&delta>=0){ A=sum[i]-sum[head-1]; B=i-head+1; return true; } }return false; }
It is your time to fight!