bzoj 5206: [Jsoi2017]原力

题意

一个原力网络可以看成是一个可能存在重边但没有自环的无向图。每条边有一种属性和一个权值。属性可能是R、G
、B三种当中的一种,代表这条边上原力的类型。权值是一个正整数,代表这条边上的原力强度。原力技术的核心
在于将R、G、B三种不同的原力融合在一起产生单一的、便于利用的原力。为了评估一个能源网络,JYY需要找到所
有满足要求的三元环(首尾相接的三条边),其中R、G、B三种边各一条。一个三元环产生的能量是其中三条边的
权值之积。
现在对于给出的原力网络,JYY想知道这个网络的总能量是多少。网络的总能量是所有满足要求三元环的能量之和。

前言

我写hash,这次居然忘记处理冲突了。。
WA了好几发QAQ
我真是SB了

题解

套路地
把度数比 m m 大的标为大点,否则标为小点
容易知道,大点之后 m m
考虑三元组三个都是大点,直接暴力枚举就可以了, m3 m 3
否则枚举一个小点,枚举它的两条边
考虑每一条边被枚举多少次,就是 m m
因为他一端的小点,只有 m m 个出度
于是就可以通过了
剩下的hash解决即可

CODE:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long LL;
const LL MOD=1e9+7;
const LL N=50005;
const LL M=100005;
const LL MOD1=1000037;
LL sum[MOD1][3];
LL X[MOD1],Y[MOD1];
LL n,m;
LL get (LL x,LL y)
{if (x>y) swap(x,y);
LL now=(x*2333+y*23333)%MOD1;
while(X[now]!=0)
{
 if (X[now]==x&&Y[now]==y) break;
    if(now==MOD1-1)now=0;
    else now++;
}
return now;
}
LL d[N];
vector<LL> a,b;
struct qq
{
    LL x,y,last;
}e[M*2];LL num,last[N];
void init (LL x,LL y)
{
    num++;
    e[num].x=x;e[num].y=y;
    e[num].last=last[x];
    last[x]=num;
}
bool ok[N];//这个点是不是大点 
LL calc (LL x,LL y,LL z)
{
    LL lalal=0;
    lalal=lalal+sum[x][0]*sum[y][1]%MOD*sum[z][2]%MOD;
    lalal=lalal+sum[x][0]*sum[y][2]%MOD*sum[z][1]%MOD;
    lalal=lalal+sum[x][1]*sum[y][0]%MOD*sum[z][2]%MOD;
    lalal=lalal+sum[x][1]*sum[y][2]%MOD*sum[z][0]%MOD;
    lalal=lalal+sum[x][2]*sum[y][0]%MOD*sum[z][1]%MOD;
    lalal=lalal+sum[x][2]*sum[y][1]%MOD*sum[z][0]%MOD;
    return lalal%MOD;
}
int main()
{
    num=0;memset(last,-1,sizeof(last));
    scanf("%lld%lld",&n,&m);
    LL size=sqrt(m)+1;
    for (LL u=1;u<=m;u++)
    {
        LL x,y,w;
        scanf("%lld%lld%lld",&x,&y,&w);
        if (x>y) swap(x,y);
        LL t=get(x,y);
    //  printf("%lld %lld %lld\n",x,y,t);
        if (X[t]==0)
        {
            X[t]=x;Y[t]=y;
            init(x,y);init(y,x);
            d[x]++;d[y]++;
        }
        char ch=getchar();
        while (ch!='R'&&ch!='G'&&ch!='B') ch=getchar();
        if (ch=='R') sum[t][0]+=w;
        if (ch=='G') sum[t][1]+=w;
        if (ch=='B') sum[t][2]+=w;
        sum[t][0]%=MOD;sum[t][1]%=MOD;sum[t][2]%=MOD;       
    }   
    for (LL u=1;u<=n;u++)
    {
        if (d[u]>=size) 
        {
        //  printf("YES:%lld\n",u);
            ok[u]=true;
            a.push_back(u);
        }
        else 
        {
            ok[u]=false;
            b.push_back(u);
        }
    }
    LL tot=a.size();
    LL ans=0;
    for (LL u=0;u<tot;u++)
        for (LL i=u+1;i<tot;i++)
        {
            LL t1=get(a[u],a[i]);
                for (LL j=i+1;j<tot;j++)
                {
                    LL t2=get(a[u],a[j]),t3=get(a[i],a[j]);
                        ans=(ans+calc(t1,t2,t3))%MOD;
                }
        }
    tot=b.size(); 
    for (LL u=0;u<tot;u++)//枚举所有小点 
    {
        LL x=b[u];
        for (LL i=last[x];i!=-1;i=e[i].last)
        {
            for (LL j=last[x];j!=-1;j=e[j].last)
            {
                LL y1=e[i].y,y2=e[j].y;
                    if (ok[y1]==false&&ok[y2]==false)
                    {
                        if (x<y1&&y1<y2)
                        {// printf("A:%lld %lld %lld\n",x,y1,y2);
                            ans=(ans+calc(get(x,y1),get(y1,y2),get(x,y2)))%MOD;
                        }
                    }
                    else if (ok[y1]==false)
                    {
                        if (x<y1)
                        {
                        //  printf("B:%lld %lld %lld %lld\n",x,y1,y2,calc(get(x,y1),get(y1,y2),get(x,y2)));
                            ans=(ans+calc(get(x,y1),get(y1,y2),get(x,y2)))%MOD;
                        }
                    }
                    else if (y1<y2&&ok[y1]&&ok[y2])
                            ans=(ans+calc(get(x,y1),get(y1,y2),get(x,y2)))%MOD;
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值