省队集训DAY3

来源:互联网 发布:python smtp ssl 编辑:程序博客网 时间:2024/05/01 06:16

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 100003using 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);}