计蒜客 部落
其实就是一道暴力题目
考虑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; }