题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4816
2013长春区域赛的D题。
很简单的几何题,就是给了一条折线。 然后一个矩形窗去截取一部分,求最大面积。
现场跪在这题,最后时刻TLE到死,用的每一小段去三分,时间复杂度是O(n log n) , 感觉数据也不至于超时。
卧槽!!!!代码拷回来,今天在HDU一交,一模一样的代码AC了,加输入外挂6s多,不加也8s多,都可AC,呵呵·····(估计HDU时限放宽了!!!)
现场赛卡三分太SXBK了,我艹!!!! 好好的一个现场赛绝杀错过了。
以下是现场赛源码,在HDU顺利AC! 现场TLE到死!
其实O(n)也可以搞,因为是三分的是一个二次函数,求对称轴就可以了。现场没有想到这个优化,等下简单修改成O(n)代码。
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <algorithm> 5 #include <queue> 6 #include <map> 7 #include <set> 8 #include <vector> 9 #include <string> 10 #include <math.h> 11 using namespace std; 12 const int MAXN = 200010; 13 int x[MAXN],y[MAXN]; 14 int d; 15 int n; 16 int L; 17 int nowx ; 18 int nextx; 19 int r1,l2; 20 const double eps = 1e-8; 21 double solve() 22 { 23 double left = nowx,right = nextx; 24 double ret1,ret2; 25 for(int cc = 0;cc <= 30;cc++) 26 { 27 double mid = (left + right)/2; 28 double midmid = (mid + right)/2; 29 double h1 = y[r1] + (double)(y[r1-1] - y[r1]) * (mid - x[r1])/(x[r1-1] - x[r1]); 30 double h2 = y[l2] + (double)(y[l2+1] - y[l2])*(mid + 2*d - x[l2])/(x[l2 + 1] - x[l2]); 31 ret1 = (double)(x[r1] - mid)*(h1 + y[r1])/2 + (double)(mid + 2*d - x[l2])*(h2 + y[l2])/2; 32 33 h1 = y[r1] + (double)(y[r1-1] - y[r1]) * (midmid - x[r1])/(x[r1-1] - x[r1]); 34 h2 = y[l2] + (double)(y[l2+1] - y[l2])*(midmid + 2*d - x[l2])/(x[l2 + 1] - x[l2]); 35 ret2 = (double)(x[r1] - midmid)*(h1 + y[r1])/2 + (double)(midmid + 2*d - x[l2])*(h2 + y[l2])/2; 36 if(ret1 < ret2) 37 left = mid+eps; 38 else right = midmid-eps; 39 } 40 return ret1; 41 } 42 43 44 int input() 45 { 46 char ch; 47 ch = getchar(); 48 while(ch < '0' || ch >'9') 49 { 50 ch = getchar(); 51 } 52 int ret = 0; 53 while(ch >= '0' && ch <= '9') 54 { 55 ret *= 10; 56 ret += ch -'0'; 57 ch = getchar(); 58 } 59 return ret; 60 } 61 62 int main() 63 { 64 //freopen("D.txt","r",stdin); 65 //freopen("out.txt","w",stdout); 66 int T; 67 scanf("%d",&T); 68 while(T--) 69 { 70 scanf("%d%d",&n,&L); 71 for(int i = 1;i <= n;i++) 72 { 73 //x[i] = input(); 74 //y[i] = input(); 75 scanf("%d%d",&x[i],&y[i]); 76 } 77 //scanf("%d%d",&x[i],&y[i]); 78 scanf("%d",&d); 79 double ans = 0; 80 r1 = 2; 81 l2 = 1; 82 double tmp = 0; 83 while(l2 < n && x[l2+1] < 2*d)l2++; 84 for(int i = r1;i < l2;i++) 85 { 86 tmp += (double)(x[i+1] - x[i])*(y[i] + y[i+1])/2; 87 } 88 if(l2 == 1) 89 { 90 tmp -= (double)(x[2] - x[1])*(y[2] + y[1])/2; 91 } 92 x[n+1] = x[n]; 93 y[n+1] = y[n]; 94 nowx = 0; 95 //printf("%d %d\n",r1,l2); 96 while(l2 < n && r1 <= n) 97 { 98 int p1 = x[r1]; 99 int p2 = x[l2 + 1] - 2*d; 100 if(p1 < p2) 101 nextx = p1; 102 else nextx = p2; 103 nextx = min(L- 2*d,nextx); 104 //printf("%d %d\n",nowx,nextx); 105 ans = max(ans,tmp + solve()); 106 if(p1 < p2) 107 { 108 nowx = p1; 109 if(r1 < n)tmp -= (double)(x[r1+1] - x[r1])*(y[r1+1] + y[r1] )/2; 110 r1++; 111 } 112 else 113 { 114 nowx = p2; 115 tmp += (double)(x[l2+1] - x[l2])*(y[l2+1] + y[l2])/2; 116 l2++; 117 } 118 } 119 printf("%.3lf\n",ans/2/d); 120 } 121 return 0; 122 }
改成了O(n)的解法。
因为三分的那个函数是二次函数。
找最大值,只要找两个端点和对称轴处就足够了!
还是太弱,现场没有想到这个优化,改起来很容易的。
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <algorithm> 5 #include <queue> 6 #include <map> 7 #include <set> 8 #include <vector> 9 #include <string> 10 #include <math.h> 11 using namespace std; 12 const int MAXN = 200010; 13 int x[MAXN],y[MAXN]; 14 int d; 15 int n; 16 int L; 17 int nowx ; 18 int nextx; 19 int r1,l2; 20 const double eps = 1e-8; 21 double solve() 22 { 23 double left = nowx,right = nextx; 24 //求出二次函数的a,b,c系数 25 double tmp11 = x[r1]; 26 double tmp12 = -1; 27 double tmp13 = (double)y[r1] - (double)x[r1]*(y[r1-1] - y[r1])/(x[r1-1] - x[r1])/2; 28 double tmp14 = (double)(y[r1-1] - y[r1])/(x[r1-1] - x[r1])/2; 29 double tmp21 = 2*d - x[l2]; 30 double tmp22 = 1; 31 double tmp23 = y[l2] + (double)(2*d - x[l2])*(y[l2+1] - y[l2])/(x[l2+1] - x[l2])/2; 32 double tmp24 = (double)(y[l2+1] - y[l2])/(x[l2+1] - x[l2])/2; 33 //函数Y = (tmp11 + tmp12 * x)*(tmp13 + tmp14 * x) + (tmp21 + tmp22 * x)*(tmp23 + tmp24*x) 34 double a = tmp12 * tmp14 + tmp22 * tmp24; 35 double b = tmp11 * tmp14 + tmp12 * tmp13 + tmp21 * tmp24 + tmp22 * tmp23; 36 double c = tmp11 * tmp13 + tmp21 * tmp23; 37 38 double x0 = -b /(2*a);//对称轴 39 double ret = max(a*left*left + b*left + c,a*right *right + b * right + c); 40 if(x0 >= left && x0 <= right) 41 ret = max(ret,a * x0 * x0 + b*x0 + c); 42 return ret; 43 44 /* 45 double ret1,ret2; 46 for(int cc = 0;cc <= 30;cc++) 47 { 48 double mid = (left + right)/2; 49 double midmid = (mid + right)/2; 50 double h1 = y[r1] + (double)(y[r1-1] - y[r1]) * (mid - x[r1])/(x[r1-1] - x[r1]); 51 double h2 = y[l2] + (double)(y[l2+1] - y[l2])*(mid + 2*d - x[l2])/(x[l2 + 1] - x[l2]); 52 ret1 = (double)(x[r1] - mid)*(h1 + y[r1])/2 + (double)(mid + 2*d - x[l2])*(h2 + y[l2])/2; 53 54 h1 = y[r1] + (double)(y[r1-1] - y[r1]) * (midmid - x[r1])/(x[r1-1] - x[r1]); 55 h2 = y[l2] + (double)(y[l2+1] - y[l2])*(midmid + 2*d - x[l2])/(x[l2 + 1] - x[l2]); 56 ret2 = (double)(x[r1] - midmid)*(h1 + y[r1])/2 + (double)(midmid + 2*d - x[l2])*(h2 + y[l2])/2; 57 if(ret1 < ret2) 58 left = mid+eps; 59 else right = midmid-eps; 60 } 61 return ret1; 62 */ 63 } 64 65 66 int input() 67 { 68 char ch; 69 ch = getchar(); 70 while(ch < '0' || ch >'9') 71 { 72 ch = getchar(); 73 } 74 int ret = 0; 75 while(ch >= '0' && ch <= '9') 76 { 77 ret *= 10; 78 ret += ch -'0'; 79 ch = getchar(); 80 } 81 return ret; 82 } 83 84 int main() 85 { 86 //freopen("D.txt","r",stdin); 87 //freopen("out.txt","w",stdout); 88 int T; 89 scanf("%d",&T); 90 while(T--) 91 { 92 scanf("%d%d",&n,&L); 93 for(int i = 1;i <= n;i++) 94 { 95 //x[i] = input(); 96 //y[i] = input(); 97 scanf("%d%d",&x[i],&y[i]); 98 } 99 //scanf("%d%d",&x[i],&y[i]); 100 scanf("%d",&d); 101 double ans = 0; 102 r1 = 2; 103 l2 = 1; 104 double tmp = 0; 105 while(l2 < n && x[l2+1] < 2*d)l2++; 106 for(int i = r1;i < l2;i++) 107 { 108 tmp += (double)(x[i+1] - x[i])*(y[i] + y[i+1])/2; 109 } 110 if(l2 == 1) 111 { 112 tmp -= (double)(x[2] - x[1])*(y[2] + y[1])/2; 113 } 114 x[n+1] = x[n]; 115 y[n+1] = y[n]; 116 nowx = 0; 117 //printf("%d %d\n",r1,l2); 118 while(l2 < n && r1 <= n) 119 { 120 int p1 = x[r1]; 121 int p2 = x[l2 + 1] - 2*d; 122 if(p1 < p2) 123 nextx = p1; 124 else nextx = p2; 125 nextx = min(L- 2*d,nextx); 126 //printf("%d %d\n",nowx,nextx); 127 ans = max(ans,tmp + solve()); 128 if(p1 < p2) 129 { 130 nowx = p1; 131 if(r1 < n)tmp -= (double)(x[r1+1] - x[r1])*(y[r1+1] + y[r1] )/2; 132 r1++; 133 } 134 else 135 { 136 nowx = p2; 137 tmp += (double)(x[l2+1] - x[l2])*(y[l2+1] + y[l2])/2; 138 l2++; 139 } 140 } 141 printf("%.3lf\n",ans/2/d); 142 } 143 return 0; 144 }