【BestCoder Round #93 1004】MG loves set
【题目链接】:http://acm.hdu.edu.cn/showproblem.php?pid=6022
【题意】
让你求一个集合的子集数目;
这个子集有要求;
即:
它所有元素的平方的和小于它所有元素的和的平方。
【题解】
假设一个集合大小为3元素为a1,a2,a3
则
a12+a22+a32<=(a1+a2+a3)2
化简一下可以得到
a1∗a2+a1∗a3+a2∗a3>=0
所以原限制条件其实可以转化为一个集合里面任意两个数的乘积的和大于等于0;
但是你不好直接去枚举这个集合的子集;
->有230的规模
这里用到了meet-in-the-middle这种方法(自行百度);
先处理215规模的;
即把整个序列分成等大的两部分;
先处理前面一半;
这前面一半;
枚举每个元素在不在子集当中;
然后算出每个子集的所有元素的和sumA
sumA=a1+a2+a3..+al
以及sqrsumA
sqrsumA=a12+a22+a32+...+al2
然后把
(sumA,(sumA2−sqrsumA)/2)
当成一个点来对待->(x,y)
注意这里的y其实就是A集合中任意两个数的乘积
然后把这个点存在kd-tree里面,并以这些点构建出一棵kd-tree;
然后再枚举序列的右半部分;
即n/2+1..n这一段
同样枚举这一段每个元素在不在子集中;
->这样又有了另外一个子集B
同样处理出sumB
sumB=b1+b2+b3..+bl
以及sqrsumB
sqrsumB=b12+b22+b32+...+bl2
然后同样的处理出下面这个点
(sumB,(sumB2−sqrsumB)/2)
这里的y变成是B集合的任意两个元素的乘积了;
然后考虑把B集合和之前的某个A集合合在一起;
那么我们要怎么搞出那个新的集合的任意两个元素的乘积呢;
那就是sumA*sumB+ya+yb了
这里sumA*sumB=a1*b1+a1*b2….
ya就是A集合任意两个数乘积的和,yb就是…
你想想两个集合连在一起后会变成什么样?
懂了吧;
所以我们现在的问题就转化为;
已经知道了直线
k*x+b+y的两个参数k和b;
然后(x,y)是A集合的那两个参数泛化成的坐标;
然后要求满足k*x+b+y>=0的(x,y)的个数;
用kd-tree能够轻松的搞定这个问题;
因为最后有两个集合都是空集的情况,所以答案要减1。
【完整代码】
#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define ps push_back
#define fi first
#define se second
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%lld",&x)
#define ref(x) scanf("%lf",&x)
#define pd(a,b,c) (a*c.d[0]+b+c.d[1]>=0)
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
const int dx[9] = { 0,1,-1,0,0,-1,-1,1,1 };
const int dy[9] = { 0,0,0,-1,1,-1,1,-1,1 };
const double pi = acos(-1.0);
const int N = 33;
const int MAXN = 65540;
int n,now,root;
LL a[N];
struct point
{
int n,sie, l, r;
LL d[2],mi_n[2],ma_x[2];
};
point t[MAXN];
bool cmp_1(point a, point b)
{
return a.d[now] < b.d[now];
}
void gengxin(int father, int son)
{
for (int i = 0; i <= 1; i++)
{
t[father].mi_n[i] = min(t[father].mi_n[i], t[son].mi_n[i]);
t[father].ma_x[i] = max(t[father].ma_x[i], t[son].ma_x[i]);
}
}
void up_data(int rt)
{
int l = t[rt].l, r = t[rt].r;
if (l)
gengxin(rt, l);
if (r)
gengxin(rt, r);
}
int build(int begin, int end, int fx)
{
int m = (begin + end) >> 1;
now = fx;
nth_element(t + begin, t + m, t + end + 1, cmp_1);
for (int i = 0; i <= 1; i++)
t[m].mi_n[i] = t[m].ma_x[i] = t[m].d[i];
t[m].sie = end - begin + 1;
if (begin < m) t[m].l = build(begin, m - 1, 1 - fx); else t[m].l = 0;
if (m < end) t[m].r = build(m + 1, end,1 - fx);else t[m].r = 0;
up_data(m);
return m;
}
LL query(int rt, point a)
{
if (!rt) return 0;
int ju = 0;
ju += pd(t[rt].mi_n[0], t[rt].mi_n[1], a);
ju += pd(t[rt].mi_n[0], t[rt].ma_x[1], a);
ju += pd(t[rt].ma_x[0], t[rt].mi_n[1], a);
ju += pd(t[rt].ma_x[0], t[rt].ma_x[1], a);
if (ju == 4)
return t[rt].sie;
if (ju == 0)
return 0;
ju = pd(t[rt].d[0], t[rt].d[1], a);
return ju + query(t[rt].l, a) + query(t[rt].r, a);
}
int main()
{
//freopen("F:\\rush.txt", "r", stdin);
int T;
rei(T);
while (T--)
{
LL ans = 0;
rei(n);
rep1(i, 1, n)
rel(a[i]);
LL l = n / 2;
rep1(i, 0, (1 << l) - 1)
{
LL sum = 0, sqrsum = 0;
rep1(j,1,l)
if (i&(1 << (j - 1)))
sum += a[j], sqrsum += a[j] * a[j];
t[i + 1].d[0] = sum, t[i + 1].d[1] = (sum*sum - sqrsum) / 2;
}
root = build(1, 1 << l, 0);
l = n - l;
rep1(i, 0, (1 << l) - 1)
{
LL sum = 0, sqrsum = 0;
rep1(j, n / 2 + 1, n)
if (i&(1 << (j - n / 2 - 1)))
sum += a[j], sqrsum+=a[j] * a[j];
point t;
t.d[0] = sum, t.d[1] = (sum*sum - sqrsum) / 2;
ans += query(root, t);
}
printf("%lld\n", ans-1);
}
//printf("\n%.2lf sec \n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
【BestCoder Round #93 1004】MG loves set的更多相关文章
- 【BestCoder Round #93 1001】MG loves gold
[题目链接]:http://acm.hdu.edu.cn/showproblem.php?pid=6019 [题意] 每次选择一段连续的段,使得这一段里面没有重复的元素; 问你最少选多少次; [题解] ...
- 【BestCoder Round #93 1002】MG loves apple
[题目链接]:http://acm.hdu.edu.cn/showproblem.php?pid=6020 [题意] 给你一个长度为n的数字,然后让你删掉k个数字,问你有没有删数方案使得剩下的N-K个 ...
- [HDU5807] [BestCoder Round #86 1004] Keep In Touch (DP)
[HDU5807] [BestCoder Round #86 1004] Keep In Touch (DP) 题面 有三个人从一张N个点无重边的有向无环图上的三个点出发,每单位时间,他们分别选择当前 ...
- 【HDU 6021】 MG loves string (枚举+容斥原理)
MG loves string Accepts: 30 Submissions: 67 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: ...
- 【HDU 6020】 MG loves apple (乱搞?)
MG loves apple Accepts: 20 Submissions: 693 Time Limit: 3000/1500 MS (Java/Others) Memory Limit: ...
- 【玲珑杯 round#18 B】图论你先敲完模板
[Link]:http://www.ifrog.cc/acm/problem/1146 [Description] [Solution] 设f[i]表示在第i个点休息的话最少需要的体力值; f[i]= ...
- 【CS Round #43 E】Coprime Pairs
[链接]点击打开链接 [题意] 让你选择n个数字,组成一个数组,使得这n个数字中恰好有k对,它们是互质的. [题解] 我们可以先找出前n个质数,那么接下来的问题就转化为,凑出rest = n*(n-1 ...
- 【CS Round #43 D】Bad Triplet
[链接]点击打开链接 [题意] 给你n个点m条边的无权无向联通图; 让你找3个点A,B,C 使得A->B=B->C=A->C 这里X->Y表示点X到点Y的最短路长度. [题解] ...
- 【CS Round #43 C】Rectangle Partition
[链接]点击打开链接 [题意] 有一辆火车,它的长度为L,然后假设这辆车现在随机可能地出现在0..D之间,然后假设它已经耗光了油. 问你它需要走的期望距离是多少. 这里要走的距离指的是车里最近的加油站 ...
随机推荐
- Django项目:CRM(客户关系管理系统)--04--02PerfectCRM创建ADMIN页面02
十.CRM项目创建模板页面 {#king_base.html#} {## ————————02PerfectCRM创建ADMIN页面————————#} {#模板文件 king_base.html#} ...
- Python判断文件和文件夹是否存在的方法
Python判断文件和文件夹是否存在的方法 这篇文章主要介绍了Python判断文件和文件夹是否存在的方法,本文还讲解了判断是否为文件或者目录的方法.os.path.lexist的作用.FTP中判断文件 ...
- Ubuntu下安装Mongo方法
场景:Ubuntu14下安装mongo,建议不要使用apt-get install 的命令安装,因为版本比较老 1.deb下载地址(可以自行选择OS,版本,server或tool或shell)http ...
- OpenLayers添加和删除控件
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- 在vue项目中同时使用element-ui和mint-ui,的时候,.babelrc配置文件怎么写
我们安装vue组件库的时候,考虑到大小问题,需要根据需要仅引入部分组件 借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的. 但是在配置 .bab ...
- POJ3614 [USACO07NOV]防晒霜Sunscreen
Sunscreen Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9333 Accepted: 3264 Descrip ...
- 【SPOJ 220】 PHRASES - Relevant Phrases of Annihilation
[链接]h在这里写链接 [题意] 给你n(n<=10)个字符串. 每个字符串长度最大为1e4; 问你能不能找到一个子串. 使得这个子串,在每个字符串里面都不想交出 ...
- 廖雪峰Python总结3
1.模块简介 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件中,这样每个文件包含的代码相对来说就比较少.一个.py文件就称之为一个模块(Module). 使用模块的好处: 提高了代码的可 ...
- 大数据技术之Flume
第1章 概述 1.1 Flume定义 Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集.聚合和传输的系统.Flume基于流式架构,灵活简单. 1.2 Flume组成架构 ...
- Codeforces 276D
题目链接 这题真的体现了自己思维的不足,考虑问题只是考虑他的特殊性,却不能总结出它的一般性规律. 对于这题, 如果L == R , 那么结果为0. 否则, 我们只需要找到最高的某一位 (二进制数中的某 ...