• BZOJ_1800_[Ahoi2009]fly 飞行棋_乱搞


    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


    分析:此题数据范围较小,有多种做法,这里只考虑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
    ", num * (num - 1) / 2);
    }
    
  • 相关阅读:
    算法提高 约数个数
    算法提高 第二大整数
    算法提高 逆序排列
    算法提高 c++_ch02_01
    算法提高 日期计算
    程序员教你设置密码
    fzu 2184 逆序数还原
    fzu 2146 Easy Game
    算法训练 区间k大数查询
    算法训练 最大最小公倍数
  • 原文地址:https://www.cnblogs.com/suika/p/8678074.html
Copyright © 2020-2023  润新知