省队集训DAY3

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/clover_hxy/article/details/72823142

T1

这里写图片描述

题解

一共要使用六根木棍,那么分割的方法就两种{1,1,1,3},{1,1,2,2}
那么关键就是要计算2,3的数量。
cnt1[i]表示每种长度的木棍的方案数
cnt2[i]最初表示用不同的木棍拼成长度为i边的方案数,后来表示选出四根木棍构成{2,2}的方案数。
cnt22[i]表示用两个长度相同的不同木棍拼成长度为i的边的方案数。
cnt3[i]表示用三根不同的木棍拼成长度为i的方案数。
考虑两个的情况,我们可以 O(n2) 的枚举两个不同的木棍,然后用cnt2[a[i]+a[j]]的答案。
关键是怎么求cnt3,cnt2.
(1)cnt3
考虑cnt3的组成枚举cnt1超过3的长度sum,然后枚举每一根单独的木棍,设长度为x。
因为cnt2中保证了两个木棍是不同的,所以只需要考虑减去枚举到的木棍计入了cnt2的情况,不合法的情况就是cnt1[sum-2*x]。还有一种特殊情况需要注意 sum=3x ,这样子cnt1[sum-2*x]中包含了x所以还需要-1.
这样计算相当于(x,y,z)三元组在枚举到x,y,z的时候都会计算一遍。所以最后的和要/3
(2)cnt2
组成情况比较复杂,首先枚举两根木棍形成的长度
1.先考虑最简单的,选中的四根木棍的长度相同,贡献是 C(cnt1[sum2/4],4)
2.(x,y,z,z)这种情况也比较好计算,答案是是 (cnt2[sum]cnt22[sum])cnt22[sum]
会不会出现(x,z,z,z),不会啊如果那样的话x=z,同第一种情况
3.(x,y,x,y)中情况等价于从 C(cnt1[x],2)C(cnt1[y],2)
4.(x,y,z,k)我们枚举sum=x+y,枚举x(这里枚举的是长度,不再是木棍)。可以确定二元组(x,y)。要求(z,k)与(x,y)不同且z!=k。答案是 (cnt2[sum]cnt22[sum]cnt1[x]cnt1[y])cnt1[x]cnt1[y] 。这种情况枚举到(x,y),(z,k)都会计算,所以最后要/2.

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 10000003
#define LL long long 
#define M 100003
using namespace std;
int n,a[M];
LL cnt1[N],cnt2[N],cnt22[N],cnt3[N],C1[N];
int q[M],m,q1[M],m1;
LL C(int x,int y)
{
    if (y>x) return 0;
    LL  t=1;
    for (int i=x-y+1;i<=x;i++) t*=(LL)i;
    for (int i=1;i<=y;i++) t/=(LL)i;
    return t;
}
int main()
{
    freopen("yist.in","r",stdin);
    freopen("yist.out","w",stdout);
    scanf("%d",&n);
    int mx=0;
    for (int i=1;i<=n;i++) {
     scanf("%d",&a[i]),cnt1[a[i]]++;
     mx=max(mx,a[i]);
    }
    for (int i=1;i<=n;i++)
     for (int j=i+1;j<=n;j++) 
      if (a[i]+a[j]<=mx) {
       cnt2[a[i]+a[j]]++;
       if (a[i]==a[j]) cnt22[a[i]+a[j]]++;
    }
    for (int i=1;i<=mx;i++) C1[i]=C(cnt1[i],2);
    for (int i=1;i<=mx;i++)
     if (cnt1[i]>=3) q[++m]=i;
    for (int i=1;i<=mx;i++)
     if (cnt1[i]) q1[++m1]=i;
    for (int i=1;i<=m;i++) {
        int sum=q[i]; LL cnt=0;
        for (int j=1;j<=n;j++) {
            if (a[j]>=sum) continue;
            int x=a[j];
            if (x*3!=sum) 
             cnt+=(LL)(cnt2[sum-x]-(sum-2*x>0?cnt1[sum-2*x]:0));
            else cnt+=(LL)(cnt2[sum-x]-(sum-2*x>0?cnt1[sum-2*x]-1:0));
        }
        cnt3[sum]+=(LL)cnt/3;
    }
    m=0;
    for (int i=1;i<=mx;i++) 
     if(cnt1[i]>=2) q[++m]=i;
    for (int i=1;i<=m;i++) {
        int x=q[i];
        LL t=cnt2[x]-cnt22[x];
        cnt2[x]=0; LL sum=0;
        for (int j=1;j<=m1;j++) {
            if (q1[j]*2==x||q1[j]>x-q1[j]) continue;
            cnt2[x]+=C1[q1[j]]*C1[x-q1[j]];
            sum+=(LL)(t-cnt1[q1[j]]*cnt1[x-q1[j]])*cnt1[q1[j]]*cnt1[x-q1[j]];
        }
        cnt2[x]+=sum/2;
        if (x*2%4==0) cnt2[x]+=C(cnt1[x*2/4],4);
        cnt2[x]+=(LL)cnt22[x]*t;
    } 
    LL ans=0;
    for (int i=1;i<=m1;i++){
        int x=q1[i];
        if (cnt1[x]<2) continue;
        ans+=C(cnt1[x],3)*cnt3[x];
        ans+=C1[x]*cnt2[x];
    }
    printf("%I64d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/clover_hxy/article/details/72823142