【HDU 4921】Map

来源:互联网 发布:java.io.file jar包 编辑:程序博客网 时间:2024/04/29 01:34

这道题在比赛的时候已经搞出来了大半,但是因为精度控制的不熟悉以及意识的模糊

导致最后也没有出来,赛后LL改了改细节和精度控制就过了,还是代码量太少了

首先可以注意到数据,给出的是最多不超过10条,最长不超过1000的链表

设cnt[i]为链i的长度,因此总的方案数fm=(cnt[1]+1)*(cnt[2]+1)*……*(cnt[n]+1)-1(题目要求至少取一个碎片)

则答案可以为总的几率/fm

因可以分别看两个部分,一个是所有碎片的总和,另一个是套装加成

先看第二个部分套装加成,对于每个套装加成,可先将该level存在的数给提取出来,我是放在t_val,right里面

right存放对应数的链表的右边还有多长

两个系数xishu,t_xishu分别表示

该链的个数不足i个的链的长度乘积,和该链的个数大于等于i个的链的长度乘积

因此可以枚举取法,然后t_xishu*xishu就是这个套装出现的次数,然后按照题意公式给出就行了

现在再来看第一个部分,因为我们已经枚举了所有的套装情况(除了1),因此只需要把上面说到的情况数*s,再加上只取一个链上的某一碎片的情况,就是第一部分的总和

最后一定要把两个部分先相加,再除以fm,因为多次除法会使得精度丢失非常厉害(fm估算可以到10^30)

代码如下:

#include<cstdio>#include<vector>#include<cstring>#include<algorithm>#define MM(a,b,c) memset(a,b,sizeof(a[0])*(c+2))using namespace std;const int SIZEN=10005;struct edge{    int to,next;};edge e[SIZEN];int val[SIZEN];int head[SIZEN],sz,in[SIZEN];int right[15],t_val[15];int ll,cnt,bit[1050];vector<int> num[15];double fm;void getbit(){    for(int i=1;i<1024;i++){        int ti=i;        for(int j=0;j<10;j++){            bit[i]+=ti&1;            ti>>=1;        }    }}void init(int n){    MM(head,-1,n);    MM(in,0,n);    sz=ll=cnt=0;}void addedge(int u,int v){    e[sz].to=v;    e[sz].next=head[u];    head[u]=sz++;    in[v]++;}void dfs(int u,int id){    num[id].push_back(u);    for(int i=head[u];i!=-1;i=e[i].next){        int v=e[i].to;        dfs(v,id);    }}void rebuild(int n){    for(int i=0;i<n;i++)        if(!in[i]){            num[cnt].clear();            dfs(i,cnt);            ll=max(ll,(int)num[cnt].size());            cnt++;        }}void debug1(){    for(int i=0;i<cnt;i++){        for(int j=0;j<num[i].size();j++) printf("%d ",num[i][j]);            printf("\n");    }}double get_ans(){    fm=1;    int ccnt;    double xishu,t_xishu;    double s,ans=0;    for(int i=0;i<cnt;i++)        fm*=(int)(num[i].size()+1);    for(int i=0;i<ll;i++){        ccnt=0;t_xishu=1;        for(int j=0;j<cnt;j++){            if(num[j].size()>=i+1){                right[ccnt]=(num[j].size()-i);                t_val[ccnt++]=val[num[j][i]];            }            else t_xishu*=(double)(num[j].size()+1);        }        for(int j=1;j<(1<<ccnt);j++){            xishu=1;s=0;            int tj=j;            for(int k=0;k<ccnt;k++){                if(tj&1){                    xishu*=right[k];                    s+=t_val[k];                }                else xishu*=i+1;                tj>>=1;            }            ans+=s*xishu*t_xishu;            if(bit[j]>=2) ans+=s*xishu*t_xishu*bit[j]/ccnt;        }    }    return ans/(fm-1);}void solve(){    int n,m;    int u,v;    scanf("%d%d",&n,&m);    init(n);    for(int i=0;i<n;i++)        scanf("%d",&val[i]);    for(int i=0;i<m;i++){        scanf("%d%d",&u,&v);        addedge(u,v);    }    rebuild(n);    double ans=get_ans();    printf("%.3lf\n",ans);}int main(){    int _;    scanf("%d",&_);    getbit();    while(_--) solve();}

0 0