HDU 5738 - Eureka
HDU 5738 - Eureka
题意:
包含两个以上共线的点的集合的个数
分析:
将所有点按(x,y)双关键字排序,排完序后所有j>i均满足xj>xi ,则接下来不会重复计数
将所有j>i的点按相对于Pi的极角排序,再逆时针扫描每条线统计
每条线的左端点Pi必须被计数,右边共m个点至少取一点为2^m -1.
因为有重点,用map记录每个点的数目.
此时重点对右侧的点没有影响,共n个左端点上至少取一点.
再加上只选取重点, (2^n - n - 1), (总状态数 - 只选取一点的状态数 - 一点都不选状态数).
所以总计(n-1)*(2^m-1) + (2^n - n - 1)。
这样枚举所有的线
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <map> 7 using namespace std; 8 #define LL long long 9 const double eps = 1e-8; 10 const double PI = 4 * atan(1); 11 const int MOD = 1e9+7; 12 struct Point 13 { 14 LL x,y; 15 bool operator < (const Point &b) const 16 { 17 return x==b.x? y<b.y : x<b.x; 18 } 19 }p[1005],pp[1005]; 20 int t,n,pos; 21 LL pow2[1005],ans; 22 map<Point,int> mp; 23 bool ccmp(const Point& a,const Point& b){//极角排序 24 LL dx1 = a.x - p[pos].x; 25 LL dy1 = a.y - p[pos].y; 26 LL dx2 = b.x - p[pos].x; 27 LL dy2 = b.y - p[pos].y; 28 return dx2 * dy1 < dx1 * dy2; 29 } 30 bool Line(const Point &a,const Point &b,const Point &c){//判断共线 31 LL dx1 = b.x - a.x; 32 LL dy1 = b.y - a.y; 33 LL dx2 = c.x - a.x; 34 LL dy2 = c.y - a.y; 35 return dx2 * dy1 == dx1 * dy2; 36 } 37 int main() 38 { 39 pow2[0]=1; 40 for(int i=1;i<=1000;i++) pow2[i] = (pow2[i-1] + pow2[i-1]) % MOD; 41 scanf("%d",&t); 42 while(t--) 43 { 44 scanf("%d",&n); 45 mp.clear(); 46 for(int i=0;i<n;i++) 47 { 48 scanf("%lld%lld",&p[i].x,&p[i].y); 49 mp[p[i]]++; 50 } 51 sort(p,p+n); 52 ans = 0; 53 for(int i=0;i<n;i++) 54 { 55 i+=mp[p[i]]-1;//最后一个重点 56 pos = i; 57 memcpy(pp,p,sizeof(p)); 58 sort(pp + i + 1, pp + n, ccmp);//极角排序 59 int u = i+1; 60 while(u<n) 61 { 62 int v = u + 1; 63 while(v<n && Line(pp[i],pp[u],pp[v]) ) v++;//找到边界 64 int m = mp[ p[i] ]; 65 ans = (ans + (pow2[v-u] - 1) * (pow2[m] - 1) % MOD ) %MOD; 66 u = v; 67 } 68 int m = mp[p[i]]; 69 ans = (ans + pow2[m] - m - 1 )%MOD; //只选取重点 70 } 71 printf("%lld\n",ans); 72 } 73 return 0; 74 }
我自倾杯,君且随意