传送门

题目大意:

给出平面上的 $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:

#include <bits/stdc++.h>
using namespace std; const int N(1e3+);
typedef long long LL;
LL mod=1e9+; struct point{
LL x, y;
void read(){
scanf("%lld%lld", &x, &y);
}
point operator-(const point &b)const{
return {x-b.x, y-b.y};
}
point operator-(){
return {-x, -y};
}
bool operator==(const point &b)const{
return x==b.x && y==b.y;
}
bool operator<(const point &b)const{
return x==b.x?y<b.y:x<b.x;
}
void out(){
cout<<x<<' '<<y<<endl;
}
LL operator^(const point &p)const{
return x*p.y-y*p.x;
}
}a[N], slope[N]; bool cmp(const int &a, const int &b){
return (slope[a]^slope[b])<; //error-prone
} int cnt[N], b[N], dup[N]; LL num[N], p[N]={}; int main(){ int T, n;
for(int i=; i<=; i++) p[i]=(p[i-]<<)%mod; for(scanf("%d", &T); T--; ){
scanf("%d", &n);
for(int i=; i<n; i++)
a[i].read(); sort(a, a+n);
for(int i=, j=, k=; i<n; j++, k=i){
for(; i<n && a[i]==a[k]; i++);
cnt[j]=i-k;
} int e=unique(a, a+n)-a; memset(num, , sizeof(num));
memset(dup, , sizeof(dup)); for(int i=; i<e; i++){ for(int j=, k=; j<e; j++){
if(i==j) continue;
slope[j]=a[j]-a[i];
if(slope[j].x<) slope[j]=-slope[j];
else if(slope[j].x== && slope[j].y<) slope[j]=-slope[j];
b[k++]=j;
} sort(b, b+e-, cmp); for(int j=, k=, sum; j<e-; k=j){
for(sum=; j<e- && (slope[b[j]]^slope[b[k]])==; sum+=cnt[b[j++]]);
num[sum+cnt[i]]+=cnt[i]; //error-prone
dup[i]++;
}
} LL _dup=, res=; for(int i=; i<e; i++) _dup+=dup[i]*(p[cnt[i]]-cnt[i]-+mod), _dup%=mod;
for(int i=; i<e; i++) res+=p[cnt[i]]-cnt[i]-+mod, res%=mod;
for(int i=; i<=n; i++)
num[i]/=i, res+=num[i]*(p[i]-i-+mod), res%=mod;
res+=mod-_dup, res%=mod;
printf("%lld\n", res);
}
}

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. vbs mytest

    public Function SaveText(filePath,content)set fso=createobject("scripting.filesystemobject" ...

  2. 开源免费的HTML5游戏引擎——青瓷引擎(QICI Engine) 1.0正式版发布了!

    青瓷引擎的成长 青瓷引擎自2015年4月项目启动开始,7月首次亮相2015年ChinaJoy,便得到业界的极大关注,随后开启限量测试,收到数百个开发者团队的试用申请及反馈,期间经历了18个内测版本,完 ...

  3. Koa框架实践与中间件原理剖析

     最近尝试用了一下Koa,并在此记录一下使用心得. 注意:本文是以读者已经了解Generator和Promise为前提在写的,因为单单Generator和Promise都能够写一篇博文来讲解介绍了,所 ...

  4. 深入理解计算机系统(2.2)---布尔代数以及C语言上的位运算

    布尔代数上的位运算 布尔代数是一个数学知识体系,它在0和1的二进制值上演化而来的. 我们不需要去彻底的了解这个知识体系,但是里面定义了几种二进制的运算,却是我们在平时的编程过程当中也会遇到的.这四种运 ...

  5. 关于Hellas和Greece

    一直以来我就好奇,为什么希腊的中文名字“希腊”和英文名字”Greece”听起来都不像(就像“德国”不像“Germany”一样),而且,为什么在很多体育比赛中看到希腊运动员的衣服上都是“Hellas”, ...

  6. GBDT(MART) 迭代决策树简介

    以下对GBDT的介绍深入浅出,非常易懂 转自:http://blog.csdn.net/w28971023/article/details/8240756 GBDT(Gradient Boosting ...

  7. Oracle学习——安装系列

    简介:Oracle Database,又名Oracle RDBMS,或简称Oracle.是甲骨文公司的一款关系数据库管理系统.它是在数据库领域一直处于领先地位的产品.可以说Oracle数据库系统是目前 ...

  8. Java面试常考知识点

    1.  什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行的字节码文件. Jav ...

  9. mysql中IFIND_IN_SET和like的区别

    在数据库中新建一张测试表t_user,包含三个字段'id','name','grilfriend',字段很容易看出,这是记录一个人的女朋友的表,注意这里的‘firlfriend’字段可以是多个人名,之 ...

  10. ubuntu下nginx的启停等常用命令

    开发过程中,我们会经常的修改nginx的配置文件,每次修改配置文件都可以先测试下本次修改的配置文件是否正确,可以利用以下命令: ? 1 service nginx -t -c /alidata/ser ...