斜率&单调队列
《浅谈数形结合思想在信息学竞赛中的应用》
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>
#include <map>
#include <string>
#include <climits>
#include <set>
#include <string>
#include <sstream>
#include <utility>
#include <ctime>
using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::greater;
const int MAXN(100010);
const int INFI((INT_MAX-1) >> 1);
char str[MAXN];
int que[MAXN];
double sum[MAXN];
int front, rear;
double get_k(int a, int b)
{
return (sum[b]-sum[a])/(b-a);
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n, l;
scanf("%d%d", &n, &l);
scanf("%s", str+1);
for(int i = 1; i <= n; ++i)
sum[i] = sum[i-1]+str[i]-'0';
front = 0;
rear = -1;
int s = 0, e = l;
double ans = get_k(s, e);
int al = l;
for(int i = l; i <= n; ++i)
{
int temp = i-l;
while(front < rear && get_k(que[rear], temp) <= get_k(que[rear-1], que[rear]))
--rear;
que[++rear] = temp;
while(front < rear && get_k(que[front], i) <= get_k(que[front+1], i))
++front;
double tans = get_k(que[front], i);
if(tans == ans && i-que[front] < al)
{
al = i-que[front];
s = que[front];
e = i;
}
else
if(tans > ans)
{
ans = tans;
al = i-que[front];
s = que[front];
e = i;
}
}
printf("%d %d\n", s+1, e);
}
return 0;
}
乘法避免误差,效率提高
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>
#include <map>
#include <string>
#include <climits>
#include <set>
#include <string>
#include <sstream>
#include <utility>
#include <ctime>
using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::greater;
const int MAXN(100010);
const int INFI((INT_MAX-1) >> 1);
char str[MAXN];
int que[MAXN];
long long sum[MAXN];
int front, rear;
inline bool check_rear(int a, int b, int c)
{
return (sum[c]-sum[b])*(b-a) <= (sum[b]-sum[a])*(c-b);
}
inline bool check_front(int a, int b, int c)
{
return (sum[c]-sum[b])*(c-a) >= (sum[c]-sum[a])*(c-b);
}
inline int check_ans(int s1, int e1, int s2, int e2)
{
long long t1 = (sum[e1]-sum[s1])*(e2-s2);
long long t2 = (sum[e2]-sum[s2])*(e1-s1);
if(t2 > t1)
return 1;
else
if(t2 == t1)
return 2;
return 0;
}
int main()
{
sum[0] = 0LL;
int T;
scanf("%d", &T);
while(T--)
{
int n, l;
scanf("%d%d", &n, &l);
scanf("%s", str+1);
for(int i = 1; i <= n; ++i)
sum[i] = sum[i-1]+str[i]-'0';
front = 0;
rear = -1;
int s = 0, e = l;
int al = l;
for(int i = l; i <= n; ++i)
{
int temp = i-l;
while(front < rear && check_rear(que[rear-1], que[rear], temp))
--rear;
que[++rear] = temp;
while(front < rear && check_front(que[front], que[front+1], i))
++front;
int flag = check_ans(s, e, que[front], i);
if(flag == 1 || (flag == 2 && i-que[front] < al))
{
s = que[front];
e = i;
al = e-s;
}
}
printf("%d %d\n", s+1, e);
}
return 0;
}