https://vjudge.net/problem/UVA-1451
题意:给定长度为n的01串,选一个长度至少为L的连续子串,使得子串中数字的平均值最大。
思路:这题需要数形结合,真的是很灵活。
入门经典上讲得很详细,或者也可以看看这个,写得很不错。浅谈树形结合思想在信息竞赛中的应用
这道题的话首先就是求前缀和,之后的平均值就相当于求斜率了。
最重要的一点,就是在用单调队列维护的时候,一定要删去上凸点。
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 5 const int maxn = 100000 + 5; 6 7 char str[maxn]; 8 int n, L; 9 int sum[maxn]; 10 int q[maxn]; 11 int front, rear; 12 13 double cacl(int a, int b) //计算斜率 14 { 15 return (double)(sum[b]-sum[a]) / (b-a); 16 } 17 18 int main() 19 { 20 //freopen("D:\\txt.txt", "r", stdin); 21 int t; 22 cin >> t; 23 while (t--) 24 { 25 cin >> n >> L >> str; 26 sum[0] = 0; 27 for (int i = 1; i <= n; i++) 28 sum[i] = sum[i - 1] + str[i - 1] - ‘0‘; 29 front = rear = -1; 30 int start = 0, end = L,len=0; 31 double ans = 0; 32 //因为长度至少为L,所以从L开始 33 for (int t = L; t <= n; t++) //t为线段右端点 34 { 35 int j = t - L; //j为线段左端点 36 //如果rear-1,rear和j是上凸点,那么删去上凸点rear 37 while (front < rear && cacl(q[rear],j) <= cacl(q[rear - 1], q[rear])) rear--; 38 //加入j 39 q[++rear] =j; 40 //第一个和t的斜率小于等于第二个和t的斜率,那么肯定取第二个,删去第一个 41 while (front < rear && cacl(q[front], t) <= cacl(q[front + 1], t)) front++; 42 //由上一步可得出t和q[front]斜率,这也就是t所能组成的最大斜率 43 double m = cacl(q[front], t); 44 int l = t - q[front] + 1; 45 if (m == ans && l<len || m>ans) 46 { 47 ans = m; 48 len = l; 49 start = q[front]; 50 end = t; 51 } 52 } 53 cout << start + 1 << " " << end << endl; 54 } 55 return 0; 56 }
原文:http://www.cnblogs.com/zyb993963526/p/6354163.html