省队集训DAY3

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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
校园悬赏任务平台对字典管理、论坛管理、任务资讯任务资讯公告管理、接取用户管理、任务管理、任务咨询管理、任务收藏管理、任务评价管理、任务订单管理、发布用户管理、管理员管理等进行集中化处理。经过前面自己查阅的网络知识,加上自己在学校课堂上学习的知识,决定开发系统选择小程序模式这种高效率的模式完成系统功能开发。这种模式让操作员基于浏览器的方式进行网站访问,采用的主流的Java语言这种面向对象的语言进行校园悬赏任务平台程序的开发,在数据库的选择上面,选择功能强大的Mysql数据库进行数据的存放操作。校园悬赏任务平台的开发让用户查看任务信息变得容易,让管理员高效管理任务信息。 校园悬赏任务平台具有管理员角色,用户角色,这几个操作权限。 校园悬赏任务平台针对管理员设置的功能有:添加并管理各种类型信息,管理用户账户信息,管理任务信息,管理任务资讯公告信息等内容。 校园悬赏任务平台针对用户设置的功能有:查看并修改个人信息,查看任务信息,查看任务资讯公告信息等内容。 系统登录功能是程序必不可少的功能,在登录页面必填的数据有两项,一项就是账号,另一项数据就是密码,当管理员正确填写并提交这二者数据之后,管理员就可以进入系统后台功能操作区。项目管理页面提供的功能操作有:查看任务,删除任务操作,新增任务操作,修改任务操作。任务资讯公告信息管理页面提供的功能操作有:新增任务资讯公告,修改任务资讯公告,删除任务资讯公告操作。任务资讯公告类型管理页面显示所有任务资讯公告类型,在此页面既可以让管理员添加新的任务资讯公告信息类型,也能对已有的任务资讯公告类型信息执行编辑更新,失效的任务资讯公告类型信息也能让管理员快速删除。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值