JZOJ 5490. 【清华集训2017模拟11.28】图染色

来源:互联网 发布:无间道3什么意思 知乎 编辑:程序博客网 时间:2024/06/06 01:16

Description

Description

Input

第一行包括两个整数N,M。
接下来M行每行两个整数u,v,代表存在一条里连接 u,v的无向边。可能存在重边自环。

Output

降序输出所有不为0的F(i) 。保留6位小数输出。

Sample Input

输入1:

5 5
1 2
2 5
3 4
4 5
3 5

输入2:

5 4
1 2
2 5
5 4
4 3

Sample Output

输出1:

3.000000
2.000000

输出2:

2.800000
2.200000

Data Constraint

对于20%的数据,n,m<=100
对于40%的数据,n,m<=5000
另外有20%的数据,保证图为一个连通的简单环,且当且仅当|u-v|=1 ,存在u到v的边。
对于100%的数据,n,m<=500000

Solution

  • 我们可以愉快的发现这种染色很快就会进入一个循环……

  • 听说可以证明循环的次数,可是我不会,就只做个十几二十轮。

  • 用哈希判断一下当前状态出现过没,出现了就说明出现了循环节!

  • 由于 F 数组的是通过取极限得到的,我们只需要保存循环节的答案即可。

  • 统计循环节的答案时要打一下标记就能均摊 O(1) 计算了。

  • 要注意一下精度问题~~。

Code

#include<cstdio>#include<cstring>#include<algorithm>#include<cctype>using namespace std;const int N=500001,mo=1e9+7,M=1e6+1;int n,m,tot,sum,pos;int first[N],next[N<<1],en[N<<1];int a[N],p[M];long long h[M],b[N],c[N],g[17][N],ans[N];inline int read(){    int X=0,w=0; char ch=0;    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();    return w?-X:X;}inline void insert(int x,int y){    next[++tot]=first[x];    first[x]=tot;    en[tot]=y;}inline int hash(int x){    int y=x%M;    while(h[y] && h[y]^x) y=(y+1)%M;    return y;}int main(){    n=read(),m=read();    for(int i=1;i<=m;i++)    {        int x=read(),y=read();        insert(x,y);        insert(y,x);    }    for(int i=1;i<=n;i++) a[i]=i;    for(int j=1,k=1;j<=n*16;j++,k=k+1>n?1:k+1)    {        for(int i=first[k];i;i=next[i])        {            c[a[en[i]]]+=k-b[en[i]];            b[en[i]]=k;            a[en[i]]=a[k];        }        //for(int i=1;i<=n;i++) c[a[i]]++;        if(k==n)        {            for(int i=1;i<=n;i++) c[a[i]]+=k-b[i];            memset(b,0,sizeof(b));            long long key=0;            for(int i=1;i<=n;i++) key=(key*10+a[i])%mo;            int k=hash(key);            if(h[k])            {                pos=p[k];                break;            }else            {                h[k]=key,p[k]=++sum;                memcpy(g[sum],c,sizeof(g[sum]));            }        }    }    for(int i=1;i<=n;i++) b[i]=c[i]-g[pos][i];    tot=0;    double num=1.0/(1.0*n*(sum-pos+1)),ext=1e-6;    for(int i=1;i<=n;i++)        if(b[i]>=ext) ans[++tot]=b[i];    sort(ans+1,ans+1+tot);    for(int i=tot;i;i--) printf("%.6lf\n",1.0*ans[i]*num);    return 0;}
阅读全文
1 0
原创粉丝点击