BZOJ_1800_[Ahoi2009]fly 飞行棋_乱搞

时间:2021-08-02 00:28:30

BZOJ_1800_[Ahoi2009]fly 飞行棋_乱搞

Description

给出圆周上的若干个点,已知点与点之间的弧长,其值均为正整数,并依圆周顺序排列。 请找出这些点中有没有可以围成矩形的,并希望在最短时间内找出所有不重复矩形。

Input

第一行为正整数N,表示点的个数,接下来N行分别为这N个点所分割的各个圆弧长度

Output

所构成不重复矩形的个数

Sample Input

8
1
2
2
3
1
1
3
3

Sample Output

3

HINT

N<= 20
BZOJ_1800_[Ahoi2009]fly 飞行棋_乱搞


分析:此题数据范围较小,有多种做法,这里只考虑O(n)的做法。

首先我们知道矩形的对角线一定是直径。并且不同的直径对应不同的矩形。

转化为两点间弧长为周长的一半的点对个数,然后求Cn2

做法1.双指针,扫一遍就出结果。

2.把弧长哈希,对每个点找一遍。

代码(哈希):

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
#define N 100050
#define LL long long
int a[N], n, p = 500009;
LL s[N], sum, num, now, d, h[500050];
void insert(LL x) {
int u = x % p;
while(h[u] != -1 && h[u] != x) u = (u + 1) % p;
h[u] = x;
}
bool find(LL x) {
int u = x % p;
while(h[u] != -1 && h[u] != x) u = (u + 1) % p;
return h[u] != -1;
}
int main() {
scanf("%d", &n);
memset(h, -1, sizeof(h));
int i, j;
for(i = 1;i <= n; ++ i) scanf("%d", &a[i]), s[i] = s[i - 1] + a[i], sum += a[i];
for(i = 1;i <= n; ++ i) insert(s[i] % sum);
if(sum % 2) {
puts("0"); return 0;
}
for(i = 1;i <= n; ++ i) num += find((s[i] + sum / 2) % sum);
num /= 2;
printf("%lld\n", num * (num - 1) / 2);
}