一开始看n<=30完全没有头绪啊。。。感觉不能二进制状压的样子qwq。
后来想了想,状态是可以压缩成 目前图中联通块大小集合 和 我们在哪个联通块的,于是开开心心整数拆分,发现n=30的时候也只有5000多,这不是怎么暴力写都能过的复杂度吗233333。
但后来写出来之后发现因为用了太多 vector 以及 map ,还有脸黒自带的大常数,T==100且n全是30的时候就TLE(本地测的)了 qwq。
于是又离线了一波,把n一样的一起回答了(因为n一样的话状态集合就是一样的),终于是过了,130ms,跑的死慢。。。。
看提交里 10ms 的用的直接是二进制状压,迷。。。。
(感觉自己白写了这么多行代码,mmp)
总结起来就是 : 不开O2少用STL 23333
/* x = 2/3 * 3 + 1/3 * 1.5 + 1 */ #include<bits/stdc++.h> #define ll unsigned long long using namespace std; #define pb push_back const int N=7005; vector<int> g[N],ask[233]; unordered_map<ll,int> mmp; int n,T,tot,a[47],m,p[47],siz[47],bg[233]; int Ge[N][35][35],pos[N][35][35],pt[233]; double f[N][35],ans[233]; bool v[N][35],hav[35]; int getf(int x){ return p[x]==x?x:(p[x]=getf(p[x]));} inline ll gethash(vector<int> x){ ll an=0; for(int i:x) an=an*37ll+(ll)i; return an; } void dfs(int x,int lef){ if(lef>=a[x]){ tot++,a[x+1]=lef; for(int i=1;i<=x+1;i++) g[tot].pb(a[i]); mmp[gethash(g[tot])]=tot; } else return; for(int i=a[x]?a[x]:a[x]+1;i*2<=lef;i++) a[x+1]=i,dfs(x+1,lef-i); } inline void init(){ for(int i=1;i<=tot;i++) g[i].clear(); tot=0,mmp.clear(),memset(v,0,sizeof(v)); dfs(0,n); for(int i=1,sz;i<=tot;i++){ sz=g[i].size(); for(int j=0;j<sz;j++) for(int k=j+1,l;k<sz;k++){ vector<int> now=g[i]; now[k]+=now[j],now[j]=0; for(l=k;l+1<sz&&now[l]>now[l+1];l++) swap(now[l],now[l+1]); pos[i][j][k]=l-1; for(l=j;l&&now[l]<now[l-1];l--) swap(now[l],now[l-1]); Ge[i][j][k]=mmp[gethash(now)]; } } } void dp(int S,int P){ if(v[S][P]) return; v[S][P]=1,f[S][P]=0; if(g[S].size()==1) return; f[S][P]=n-1; for(int i=0,tx,ty;i<P;i++){ tx=Ge[S][i][P],ty=pos[S][i][P]; dp(tx,ty),f[S][P]+=f[tx][ty]*g[S][i]; } for(int i=g[S].size()-1,tx,ty;i>P;i--){ tx=Ge[S][P][i],ty=pos[S][P][i]; dp(tx,ty),f[S][P]+=f[tx][ty]*g[S][i]; } f[S][P]/=(double)(n-g[S][P]); } inline void solve(){ for(int i=1;i<=30;i++) if(hav[i]){ n=i,init(); for(int j=1,tx,ty;j<=T;j++) if(pt[j]==i){ tx=mmp[gethash(ask[j])],ty=bg[j]; dp(tx,ty),ans[j]=f[tx][ty]; } } } int main(){ scanf("%d",&T); for(int i=1;i<=T;i++){ scanf("%d%d",&n,&m),pt[i]=n,hav[n]=1; for(int j=1;j<=n;j++) p[j]=j,siz[j]=1; for(int j=1,uu,vv;j<=m;j++){ scanf("%d%d",&uu,&vv); uu=getf(uu),vv=getf(vv); if(uu!=vv) p[uu]=vv,siz[vv]+=siz[uu]; } for(int j=1;j<=n;j++) if(getf(j)==j) ask[i].pb(siz[j]); sort(ask[i].begin(),ask[i].end()); for(int j=0;j<ask[i].size();j++) if(ask[i][j]==siz[getf(1)]){ bg[i]=j; break; } } solve(); for(int i=1;i<=T;i++) printf("Case %d: %.11lf ",i,ans[i]); return 0; }