一开始看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;
}