题意

给一个联通无向图,有n个点和m条边,要求用k种颜色为其染色,使得相邻的两个点颜色不同。n-m≤5,n、m≤100,000。k很大。


 

思考

若n、m≤8,用最小表示(例如,染色[1,5,3,1]<=>[1,3,2,1])。对于一种染色的最小表示,若使用了m种不同的颜色,最后的结果乘以k!/(k-m)!即可。

考虑到边数与点数的差很小,尝试将原图缩小。

第一种点:度数为1。此时可以直接删除,最后答案乘以k-1。

第二种点:度数为2。此时可以将与它相邻的两个点连起来,并附上新的边权。最后对于一种暴力的染色方案,相应的边乘以相应的边权即可。

这样边权就分为两种,一种是两端点颜色不同,一种是两端点颜色相同。我们又知道,对于长度相同的链,无论在哪,最后缩成一条边的贡献一定是一样的。

设type0[i]表示两端点颜色不同,这条边上有i-1个点(为什么i-1,因为方便边权相加)不同的方案数,type1[i]表示两端点颜色相同,i-1个点不同的方案数。

type0[i]=type1[i-1]+type0[i-1]*(k-2)

type1[i]=type1[i-1]*(k-2)+type1[i-2]*(k-1)

初始值

type0[1]=1
type0[2]=k-2
type1[2]=k-1

缩完边后暴力统计答案。

O(nm3n),这里n≤10,m≤15。


 

在脑抽情况下写出的代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long int ll;
  4 const ll maxn=1E5+15;
  5 const ll mod=1E9+7;
  6 ll n,m,k,type0[maxn],type1[maxn],x,y,in[maxn],gg=1,cur,c[maxn],top,back[maxn],ti,ans,what[maxn],vis[maxn];
  7 ll flag;
  8 ll inv[maxn];
  9 vector<int>E[maxn];
 10 map<pair<int,int>,int>w;
 11 pair<int,int> M(int x,int y)
 12 {
 13     if(x>y)swap(x,y);
 14     return make_pair(x,y);
 15 }
 16 void erase(vector<int>&S,int x)
 17 {
 18     for(vector<int>::iterator pt=S.begin();;++pt)
 19         if(*pt==x){S.erase(pt);break;}
 20 }
 21 void add(int u,int v)
 22 {
 23     E[u].push_back(v);
 24     E[v].push_back(u);
 25     w[M(u,v)]=1;
 26 }
 27 void merge(int x,int u,int v)
 28 {
 29     erase(E[u],x);
 30     erase(E[v],x);
 31     erase(E[x],u);
 32     erase(E[x],v);
 33     add(u,v);
 34     ll g1=w[M(u,x)],g2=w[M(x,v)];
 35     w[M(u,x)]=w[M(x,v)]=0;
 36     w[M(u,v)]=g1+g2;
 37     in[x]=0;
 38     --cur;
 39 }
 40 void dfs1(int u)
 41 {
 42     vis[u]=flag;
 43     for(int i=0;i<E[u].size();++i)
 44     {
 45         int v=E[u][i];
 46         if(vis[v]==flag)continue;
 47         dfs1(v);
 48         if(in[v]==1)
 49         {
 50             erase(E[u],v);
 51             erase(E[v],u);
 52             --in[v],--in[u];
 53             gg=gg*(k-1)%mod;
 54             --cur;
 55         }
 56     }
 57 }
 58 void paint(int u)
 59 {
 60     back[u]=++ti;
 61     what[ti]=u;
 62     vis[u]=1;
 63     for(int i=0;i<E[u].size();++i)
 64     {
 65         int v=E[u][i];
 66         if(vis[v])continue;
 67         paint(v);
 68     }
 69 }
 70 ll qpow(ll x,ll y)
 71 {
 72     ll ans=1,base=x;
 73     while(y)
 74     {
 75         if(y&1)ans=ans*base%mod;
 76         base=base*base%mod;
 77         y>>=1;
 78     }
 79     return ans;
 80 }
 81 void get()
 82 {
 83     ll sum=gg;
 84     for(int u=1;u<=cur;++u)
 85     {
 86         for(int i=0;i<E[what[u]].size();++i)
 87         {
 88             int v=E[what[u]][i];
 89             if(u>back[v])continue;
 90             if(c[u]==c[back[v]])sum=sum*type1[w[M(what[u],v)]]%mod;
 91             else sum=sum*type0[w[M(what[u],v)]]%mod;
 92         }
 93     }
 94     sum=sum*inv[k]%mod*qpow(inv[k-top],mod-2)%mod;
 95     ans=(ans+sum)%mod;
 96 }
 97 void dfs(int s)
 98 {
 99     if(s==cur+1){get();return;}
100     for(int i=1;i<=top;++i)
101     {
102         c[s]=i;
103         for(int j=0;j<E[what[s]].size();++j)
104         {
105             int v=E[what[s]][j];
106             if(back[v]>=s)continue;
107             if(c[s]==c[back[v]]&&type1[w[M(what[s],v)]]==0)goto end;
108             else if(type0[w[M(what[s],v)]]==0)goto end;
109         }
110         dfs(s+1);
111         end:;
112     }
113     ++top;
114     c[s]=top;
115     dfs(s+1);
116     --top;
117 }
118 void init()
119 {
120     type0[1]=1;
121     type0[2]=k-2;
122     type1[2]=k-1;
123     for(int i=3;i<=n;++i)
124     {
125         type0[i]=(type1[i-1]%mod+type0[i-1]*(k-2)%mod)%mod;
126         type1[i]=(type1[i-1]*(k-2)%mod+type1[i-2]*(k-1)%mod)%mod;
127     }
128     inv[0]=1;
129     for(int i=1;i<=k;++i)inv[i]=inv[i-1]*i%mod;
130 }
131 int main()
132 {
133     freopen("7_1.in","r",stdin);
134     ios::sync_with_stdio(false);
135     cin>>n>>m>>k;
136     init();
137     for(int i=1;i<=m;++i)
138     {
139         cin>>x>>y;
140         add(x,y);
141         ++in[x],++in[y];
142     }
143     cur=n;
144     for(int i=1;i<=n;++i)if(in[i]==1){++flag;dfs1(i);}
145     memset(vis,0,sizeof(vis));
146     for(int i=1;i<=n&&cur>3;++i)
147         if(in[i]==2&&w[M(E[i][0],E[i][1])]==0)merge(i,E[i][0],E[i][1]);
148     for(int i=1;i<=n;++i)
149     {
150         if(E[i].size()!=0)
151         {
152             paint(i);
153             break;
154         }
155     }
156     dfs(1);
157     cout<<ans<<endl;
158     return 0;
159 }
View Code

 

 posted on 2019-04-03 18:18  GreenDuck  阅读(177)  评论(0编辑  收藏  举报