传送门

题目大意:

给出平面上的 $n$ 个点,每个点有唯一的标号(label),这 $n$ 个标号的集合记作 $S$,点可能重合。求满足下列条件的 $S$ 的子集 $T$ 的数目:

1. $|T|\ge 2$

2. $T$中的点共线

Solution:

只包含一种点的符合条件的子集 $T$ 的数目很容易计算,以下我们只考虑其中至少有两种不同(指坐标不同,下同)点的符合条件的子集$T$(以下简称子集)的数目。

考虑过两不同点 $u, v$ 的直线上的点,将这些点的集合记作 $P_{uv}$,考虑 $P_{uv}$ 的子集对答案的贡献 $C_{u,v}$ 。

设 $|P_{uv}|=k$,则 $C_{uv}=2^k-k-1-\text{single}(P_{uv})$,其中 $\text{single}(P_{uv})$ 指 $P_{uv}$ 的只包含一种点的子集 $T$ 的数目。

现在固定 $u$,计算一共能得到几个 $P_{uv}$。这可通过以 $u$ 为基点,对(去重后的)其他点作极角排序来做到。

以每个点为基点做一次极角排序,这样每个点集 $P_{uv}$ 都被重复计算了 $|P_{uv}|$ 次。

我们用 $f[k]$ 表示模为 $k$ 的点集 $P_k$ 出现的次数。这个次数被重复计算了$k$次,$P_k$出现的次数为$\frac{f[k]}{k}$

则所有$P_k$贡献的子集的数目为

\[\frac{f[k]}{k}(2^k-k-1)-\sum\limits_{P_k}\text{single}(P_k),\]

故总计数为

\[\sum_{k=2}^{n}{\frac{f[k]}{k} 2^k-(k+1)} -\sum_{k=2}^{n}{\sum\limits_{P_k}\text{single}(P_k)}\]

为了计算$\sum_{k=2}^{n}{\sum\limits_{P_k}\text{single}(P_k)}$,另外维护一个数组 $d$,$d[u]$ 表示 $u$ 在多少个点集 $P$ 中出现过。

从而有

\[\sum_{k=2}^{n}{\sum_{P_k}\text{single}(P_k)}=\sum_{u=1}^{m}d[u]*(2^{c[u]}-c[u]-1),\]

其中 $m$ 指去重后的点数,$c[u]$ 表示与 $u$ 重合的点数。

Implement:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. const int N(1e3+);
  5. typedef long long LL;
  6. LL mod=1e9+;
  7.  
  8. struct point{
  9. LL x, y;
  10. void read(){
  11. scanf("%lld%lld", &x, &y);
  12. }
  13. point operator-(const point &b)const{
  14. return {x-b.x, y-b.y};
  15. }
  16. point operator-(){
  17. return {-x, -y};
  18. }
  19. bool operator==(const point &b)const{
  20. return x==b.x && y==b.y;
  21. }
  22. bool operator<(const point &b)const{
  23. return x==b.x?y<b.y:x<b.x;
  24. }
  25. void out(){
  26. cout<<x<<' '<<y<<endl;
  27. }
  28. LL operator^(const point &p)const{
  29. return x*p.y-y*p.x;
  30. }
  31. }a[N], slope[N];
  32.  
  33. bool cmp(const int &a, const int &b){
  34. return (slope[a]^slope[b])<; //error-prone
  35. }
  36.  
  37. int cnt[N], b[N], dup[N];
  38.  
  39. LL num[N], p[N]={};
  40.  
  41. int main(){
  42.  
  43. int T, n;
  44. for(int i=; i<=; i++) p[i]=(p[i-]<<)%mod;
  45.  
  46. for(scanf("%d", &T); T--; ){
  47. scanf("%d", &n);
  48. for(int i=; i<n; i++)
  49. a[i].read();
  50.  
  51. sort(a, a+n);
  52. for(int i=, j=, k=; i<n; j++, k=i){
  53. for(; i<n && a[i]==a[k]; i++);
  54. cnt[j]=i-k;
  55. }
  56.  
  57. int e=unique(a, a+n)-a;
  58.  
  59. memset(num, , sizeof(num));
  60. memset(dup, , sizeof(dup));
  61.  
  62. for(int i=; i<e; i++){
  63.  
  64. for(int j=, k=; j<e; j++){
  65. if(i==j) continue;
  66. slope[j]=a[j]-a[i];
  67. if(slope[j].x<) slope[j]=-slope[j];
  68. else if(slope[j].x== && slope[j].y<) slope[j]=-slope[j];
  69. b[k++]=j;
  70. }
  71.  
  72. sort(b, b+e-, cmp);
  73.  
  74. for(int j=, k=, sum; j<e-; k=j){
  75. for(sum=; j<e- && (slope[b[j]]^slope[b[k]])==; sum+=cnt[b[j++]]);
  76. num[sum+cnt[i]]+=cnt[i]; //error-prone
  77. dup[i]++;
  78. }
  79. }
  80.  
  81. LL _dup=, res=;
  82.  
  83. for(int i=; i<e; i++) _dup+=dup[i]*(p[cnt[i]]-cnt[i]-+mod), _dup%=mod;
  84. for(int i=; i<e; i++) res+=p[cnt[i]]-cnt[i]-+mod, res%=mod;
  85. for(int i=; i<=n; i++)
  86. num[i]/=i, res+=num[i]*(p[i]-i-+mod), res%=mod;
  87. res+=mod-_dup, res%=mod;
  88. printf("%lld\n", res);
  89. }
  90. }

UPD

在以某个点为基点进行极角排序需要进行一个将待排序的向量规范化(formalization)的过程, 具体的说就是保证各向量满足:

x>0 或 x==0 && y>0 (待排序都是非零向量)

题解上给出的做法更好一些:

想将输入的点去重后,按照字典序排序, 然后从左到右扫, 当扫到第$i$个点$p_i$时我们统计由$p_i$及其右面的点构成的且一定包含$p_i$的共线子集的数目, 统计的方法和前面类似.

这样做的好处是

1. 向量自然规范化

2. 不重不漏

Implementation:

HDU 5738 Eureka的更多相关文章

  1. HDU 5738 Eureka 统计共线的子集个数

    Eureka 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5738 Description Professor Zhang draws n poin ...

  2. HDU 5738 Eureka(极角排序)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5738 [题目大意] 给出平面中一些点,在同一直线的点可以划分为一个集合,问可以组成多少包含元素不少 ...

  3. hdu 5738 Eureka 极角排序+组合数学

    Eureka Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Subm ...

  4. hdu 5738 2016 Multi-University Training Contest 2 Eureka 计数问题(组合数学+STL)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5738 题意:从n(n <= 1000)个点(有重点)中选出m(m > 1)个点(选出的点只 ...

  5. 2016 Multi-University Training Contest 2题解报告

    A - Acperience HDU - 5734 题意: 给你一个加权向量,需要我们找到一个二进制向量和一个比例因子α,使得|W-αB|的平方最小,而B的取值为+1,-1,我们首先可以想到α为输入数 ...

  6. 2016 Multi-University Training Contest 2 - 1005 Eureka

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5738 题目大意:给定平面上的n个点,一个集合合法当且仅当集合中存在一对点u,v,对于集合中任意点w,均 ...

  7. HDU 3746:Cyclic Nacklace(KMP循环节)

    Cyclic Nacklace Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  8. HDOJ 2111. Saving HDU 贪心 结构体排序

    Saving HDU Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  9. 【HDU 3037】Saving Beans Lucas定理模板

    http://acm.hdu.edu.cn/showproblem.php?pid=3037 Lucas定理模板. 现在才写,noip滚粗前兆QAQ #include<cstdio> #i ...

随机推荐

  1. TinyFrame升级之六:全局日志的设计及实现

    日志记录显然是框架设计中不可或缺的元素,在本框架中,我们将使用log4net作为日志记录的主体.下面来具体说明如何让框架继承log4net,并通过Autofac进行IOC注入. 首先,定义好我们的Lo ...

  2. c#邮件发送的实现

    第一步 :引用命名空间 using System.Net; using System.Net.Mail; 第二步:具体代码 //创建邮箱信息 MailMessage myMail = new Mail ...

  3. 拦截PHP各种异常和错误,发生致命错误时进行报警,万事防患于未然

    在日常开发中,大多数人的做法是在开发环境时开启调试模式,在产品环境关闭调试模式.在开发的时候可以查看各种错误.异常,但是在线上就把错误显示的关闭. 上面的情形看似很科学,有人解释为这样很安全,别人看不 ...

  4. React-Native运行知乎日报遇到的问题

    研究几天RN(React-Native)后,跟着官方的demo做了一下电影图片显示的那个,但是总感觉官方的demo欠缺点什么,所以找来找去找到了RN版的知乎日报,话说知乎日报什么版的都有,不信你们上网 ...

  5. .Net分布式异常报警系统-客户端及服务端API

    客户端 客户端的作用就是捕获未处理异常, 发送异常到服务端. 关于捕获未处理异常的方法参考 http://www.cnblogs.com/youring2/archive/2012/04/25/246 ...

  6. 继续研究NDK

    继续研究NDK 我在阿里云服务器上搭建了Android ndk的开发平台,并且借助这一平台研究了NDK的内部细节. NDK提供了Android本地编程的接口,让你可以开发高效的依赖库,提高程序的速度, ...

  7. 优秀开源代码解读之JS与iOS Native Code互调的优雅实现方案

    简介 本篇为大家介绍一个优秀的开源小项目:WebViewJavascriptBridge. 它优雅地实现了在使用UIWebView时JS与ios 的ObjC nativecode之间的互调,支持消息发 ...

  8. SNMP 原理与实战详解

    原文地址:http://freeloda.blog.51cto.com/2033581/1306743 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法 ...

  9. 准确率P 召回率R

    Evaluation metricsa binary classifier accuracy,specificity,sensitivety.(整个分类器的准确性,正确率,错误率)表示分类正确:Tru ...

  10. Go--避免SQL注入

    避免SQL注入 什么是SQL注入 SQL注入攻击(SQL Injection),简称注入攻击,是Web开发中最常见的一种安全漏洞.可以用它来从数据库获取敏感信息,或者利用数据库的特性执行添加用户,导出 ...