三角形

TanYz的三角形

发布时间: 2017年12月11日 14:05   最后更新: 2017年12月11日 14:46   时间限制: 1000ms   内存限制: 128M

TanYz在熬夜打CF(伪),发现A题是一个水题,题意为判断3条线段是否能组成1个三角形。

秒掉A题之后,发现B题虽然与A题相似,但是TanYz看得一脸懵逼,完全不会。

想到CF(伪)又要掉分,TanYz感觉这辈子上红名无望,在绝望中打出GG。

不过相信身为dalao的你一定能帮TanYz秒掉这道题,请你帮帮TanYz.

第一行输入一个整数T,表示数据组数。(1 <= T <= 10)
对于每组数据,第一行输入一个整数n,表示线段条数。(1 <= n <= 100000)
第二行输入n个整数ai表示每条线段的长度。(1 <= ai <= 1000)

对于每组数据,输出一行,能构成三角形的方案数。

4
1 2 3 4
4
1 1 1 1
1
4

题意 : 选出3条边,可以构成三角形,问有多少种方案,暴力的话,3个for肯定是超时,其实就是分成3种情况去考虑
   1 . 三条边都相等的情况 , 比较简单好想。
   2 . 仅有两条边相等的情况,这个也算好想,就是有个坑 要注意下,就是要判断下较短的两条边的和大于第三条边,写的时候忘记了,一直wa !!
   3 . 当三条边都不相等的时候,那么3条边一定就有一个顺序,为了确保不重复,可以先枚举一条最小的边,在枚举一条次小边,那么第三条边就可以通过三角形的三边关系来确定,找到第三条变得额范围,要看这个范围有多少个点时,可以通过前缀和来搞定。
代码示例 :
int pre[100005];
int pp[10005];

ll fun(int x){
    return 1ll*x*(x-1)*(x-2)/6;
}

ll fun2(int x, int y){
    return 1ll*x*(x-1)/2*y;
}

int ff(int x){
    if (x < 0) return -x;
    else return x;
}

int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int t, n, x;
    
    cin >> t;
    while(t--){
        cin >> n;
        memset(pre, 0, sizeof(pre));
        for(int i = 1; i <= n; i++){
            scanf("%d", &x);
            pre[x]++;
        }
        
        memset(pp, 0, sizeof(pp));
        for(int i = 1; i <= 1000; i++){
            pp[i] = pre[i];
            pp[i] = pp[i] + pp[i-1];        
        }
        
        ll ans = 0;
        for(int i = 1; i <= 1000; i++){
            if (pre[i] >= 3) ans += fun(pre[i]);
        }
        //printf("*%lld
", ans);
        for(int i = 1; i <= 1000; i++){
            if (pre[i] >= 2){
                for(int j = 1; j <= 1000; j++){
                    if (j == i) continue;
                    if (pre[j] && i+i > j)
                        ans += fun2(pre[i], pre[j]);
                }
            }
        }
        //printf("**%lld
", ans);
        for(int i = 1; i <= 1000; i++){
            for(int j = i+1; j <= 1000; j++){
                if (pre[i] && pre[j]) {
                   int p = max(ff(i-j+1), j);
                   int u = i + j - 1;
                   if (u > 1000) u = 1000;
                   ans += 1ll*pre[i]*pre[j]*(pp[u] - pp[p]);        
                }
            }
        }
        printf("%lld
", ans);
    }

    return 0;
}
东北日出西边雨 道是无情却有情
原文地址:https://www.cnblogs.com/ccut-ry/p/8029631.html