BZOJ 1800(思维)

传送门

题面:

1800: [Ahoi2009]fly 飞行棋

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 2267  Solved: 1733
[Submit][Status][Discuss]

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^4)。

    但是这个题还是可以把复杂度继续压下来的。

    考虑到题目中要我们求的是矩形,根据矩形在圆内的性质,不难发现,一个矩形是由两条相交的直径构成的。因此倘若我们知道了n个点可以构成的直径的个数,则最终的答案即为C(直径,2)。

    而继续根据同弧所对的圆周角=圆心角的一半,我们知道,一段弧长为直径,当且仅当弧长为周长的一半。因此我们现在只需要枚举两个点,不断判断这两个点是否是直径即可。此时的时间复杂度为O(n^2)。

代码:

//O(n^4)
#include <bits/stdc++.h>
#define maxn 25
using namespace std;
int sum[maxn];
int a[maxn];
int main()
{
    int n;
    //freopen("in.txt","r",stdin);
    scanf("%d",&n);
    int tot=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    int res=0;
    for(int a=1;a<=n;a++)
    for(int b=a+1;b<=n;b++)
    for(int c=b+1;c<=n;c++)
    for(int d=c+1;d<=n;d++){
        if((sum[b]-sum[a]==sum[d]-sum[c])&&(sum[n]-sum[d]+sum[a]==sum[c]-sum[b]))
        res++;
    }
    cout<<res<<endl;
}
//O(n^2)
#include <bits/stdc++.h>
#define maxn 25
using namespace std;
int sum[maxn];
int a[maxn];
int main()
{
   // freopen("in.txt","r",stdin);
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    int cnt=0;
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            if(sum[j]-sum[i]==sum[n]/2) cnt++;
        }
    }
    cout<<cnt*(cnt-1)/2<<endl;
}
原文地址:https://www.cnblogs.com/Chen-Jr/p/11007183.html