• 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);
    }
    
  • 相关阅读:
    JavaScript高度和宽度详解
    VC6程序图标
    VC++中的Dlg,App,Doc,view
    Vista桌面图标无法拖动
    VC2008中IE8脚本错误问题解决
    单文件安装包制作(转)
    AutoResetEvent与ManualResetEvent区别
    纯JavaScript中调用WebServices
    动态加载程序集Assembly.Load
    VC++小知识积累
  • 原文地址:https://www.cnblogs.com/suika/p/8678074.html
Copyright © 2020-2023  润新知