计蒜客 部落

其实就是一道暴力题目

考虑x部落和y部落,如果x人数多swap(x,y)

然后考虑算贡献

枚举x部落中的每一个人

ans=对于每一个人y中比这个人弱的个数*val[x]+比它强的人和(前缀和一下)

显然这是会被卡的

但是只要加个map记录一下已经算过的x,y就行了

代码如下:

#include<bits/stdc++.h>
#define pi pair<int,int>
#define mk make_pair
#define N 500005
using namespace std;
int n,x,y,Q,c[N];double fenmu,ans=0;
vector<int>G[N];
vector<double>sum[N];
map<pi,double>mp;
inline void solve(int val,int x){
    int num=upper_bound(G[x].begin(),G[x].end(),val)-G[x].begin()+1;
    //cerr<<"pos:  "<<num<<endl;
    ans=ans+1.0*val*(num-1)/fenmu;
    ans=ans+1.0*sum[x][(int)G[x].size()]/fenmu-1.0*sum[x][num-1]/fenmu;
}
int main(){
    //freopen("tribe7.in","r",stdin);
    //freopen("out.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
        scanf("%d",&c[i]);
        for (int j=1;j<=c[i];j++){
            scanf("%d",&x);
            G[i].push_back(x);
        }
    }
    for (int i=1;i<=n;i++) sort(G[i].begin(),G[i].end());
    for (int i=1;i<=n;i++){
        for (int j=0;j<=(int)G[i].size();j++) sum[i].push_back(0);
        for (int j=0;j<(int)G[i].size();j++) sum[i][j+1]=sum[i][j]+1.0*G[i][j];
    }
    /*for (int i=1;i<=n;i++){
        for (int j=1;j<=(int)G[i].size();j++) printf("%d ",sum[i][j]);
        puts("");
    }*/
    //cerr<<upper_bound(G[2].begin(),G[2].end(),2)-G[2].begin()<<endl;
    scanf("%d",&Q);
    while (Q--){
        scanf("%d%d",&x,&y);
        if (G[x].size()>G[y].size()) swap(x,y);
        pi tmp=mk(x,y);
        if (mp[tmp]){printf("%.4lf\n",mp[tmp]);continue;}ans=0;
        fenmu=(double)(G[x].size())*((double)G[y].size());
        for (int i=0;i<(int)G[x].size();i++) solve(G[x][i],y);
        //cerr<<G[x].size()<<" "<<G[y].size()<<endl;
        mp[tmp]=ans;
        printf("%.4lf\n",mp[tmp]);
    }
    return 0;
}

 

posted @ 2018-08-12 22:32  longint  阅读(123)  评论(0编辑  收藏  举报