【ZJOI 2018】线图(树的枚举,hash,dp)
2018-04-01 13:46
369 查看
线图
题目描述
九条可怜是一个热爱出题的女孩子。
今天可怜想要出一道和图论相关的题。在一张无向图 $G$ 上,我们可以对它进行一些非常有趣的变换,比如说对偶,又或者说取补。这样的操作往往可以赋予一些传统的问题新的活力。例如求补图的连通性、补图的最短路等等,都是非常有趣的问题。
最近可怜知道了一种新的变换:求原图的线图 (line graph)。对于无向图 $G = ⟨V, E⟩$,它的 线图 $L(G)$ 也是一个无向图:
- 它的点集大小为 $|E|$,每个点唯一对应着原图的一条边。
- 两个点之间有边当且仅当这两个点对应的边在原图上有公共点(注意不会有自环)。 下图是一个简单的例子,左图是原图,右图是它对应的线图。其中点 $1$ 对应原图的边 $(1, 2)$,点 $2$ 对应 $(1, 4)$,点 $3$ 对应 $(1, 3)$,点 $4$ 对应 $(3, 4)$。
#include <cstdio> #include <map> #include <cmath> #include <cstdlib> #include <cstring> #include <vector> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; typedef pair<int, int> Pair; #define fir first #define sec second #define Mp make_pair typedef vector<int>::iterator Vecit; typedef vector<Pair>::iterator Vecpa; const int N = 5005, MOD = 998244353, M = 11, NM = 110005; int Ans; int n, K; int fa , A[1<<23], pd[M][M], C [23]; int dg[NM], dgr[NM], dgs[NM]; int dp [M], gp[2][1<<M]; vector<Pair> E, B[NM]; vector<int> G , T ; inline void Add(int a, int b) { G[a].push_back(b); } inline void Ad(int &a, int b) { a+=b; (a>=MOD)? (a-=MOD):(0); } inline int Last_pos(int x, int res=0) { for (x&=(-x); x; x>>=1) ++res; return res; } inline int Count(int x, int res=0) { for (; x; x>>=1) res+=x&1; return res; } #define Sqr(x) ((LL)(x)*(x)) #define _c2(x) ((LL)(x)*((x)-1)/2) inline int Calc(int n, int m, int K, int res=0) { if (K==1) return m; memset(dg, 0, sizeof(int)*(n+1)); memset(dgr, 0, sizeof(int)*(n+1)); memset(dgs, 0, sizeof(int)*(n+1)); for (Vecpa p=E.begin(); p!=E.end(); ++p) ++dg[(*p).fir], ++dg[(*p).sec]; if (K==2) { for (int *i=dg+1; i<=dg+n; ++i) res=(res+_c2(*i))%MOD; return res; } if (K==3) { for (Vecpa p=E.begin(); p!=E.end(); ++p) res=(res+_c2(dg[(*p).fir]+dg[(*p).sec]-2))%MOD; return res; } if (K==4) { for (Vecpa p=E.begin(); p!=E.end(); ++p) { int u=(*p).fir, v=(*p).sec, X=dg[u]+dg[v]-2; dgr[u]=(dgr[u]+(LL)X*X)%MOD; dgr[v]=(dgr[v]+(LL)X*X)%MOD; Ad(dgs[u], X); Ad(dgs[v], X); } for (int i=1; i<=n; ++i) { int sqr=dgr[i], sum=dgs[i], deg=dg[i]; res=(res+(LL)sum*sum-sqr+(LL)sqr*(deg-1)-(LL)5*(deg-1)*sum+(LL)6*_c2(deg))%MOD; } return (LL)res*(MOD+1)/2%MOD; } int cnt=0; for (int i=0; i<=n; ++i) B[i].clear(); for (Vecpa p=E.begin(); p!=E.end(); ++p) { B[(*p).fir].push_back(Mp((*p).sec, ++cnt)); B[(*p).sec].push_back(Mp((*p).fir, cnt)); } E.clear(); for (int i=1; i<=n; ++i) for (int j=0; j<(int)B[i].size(); ++j) for (int k=0; k<j; ++k) E.push_back(Mp(B[i][j].sec, B[i][k].sec)); return Calc(m, (int)E.size(), K-1); } inline void Get_dp(int x, int Fa, int K) { for (Vecit p=G[x].begin(); p!=G[x].end(); ++p) if (*p!=Fa) { Get_dp(*p, x, K); } for (int i=1; i<=K; ++i) { int flg=0; for (int j=1; j<i; ++j) if (pd[i][j]) { dp[x][i]=dp[x][j]; flg=1; break; } if (flg) continue; int cnt=0; vector<int> L; for (Vecit p=T[i].begin(); p!=T[i].end(); ++p) if (*p!=fa[i]) { if ((int)T[*p].size()==1) ++cnt; else L.push_back(*p); } if (cnt+(int)L.size() > (int)G[x].size()-(x!=1)) continue; int ST=1<<(int)L.size(), ls=0, no=1; memset(gp[0], 0, sizeof(int)*(ST)); memset(gp[1], 0, sizeof(int)*(ST)); gp[no][0]=1; for (Vecit v=G[x].begin(); v!=G[x].end(); ++v) if (*v!=Fa) { int ns=0; for (int j=0; j<(int)L.size(); ++j, ns=0) if (dp[*v][L[j]]){ for (int k=0; k<j; ++k) if (pd[L[j]][L[k]]) ns|=1<<k; int U=(ST-1)^ns^(1<<j); for (int sub=U; sub; sub=(sub-1)&U) { Ad(gp[ls][sub|ns|(1<<j)], (LL)dp[*v][L[j]]*gp[no][sub|ns]%MOD); } Ad(gp[ls][ns|(1<<j)], (LL)dp[*v][L[j]]*gp[no][ns]%MOD); } for (int st=0; st<ST; ++st) { Ad(gp[ls][st], gp[no][st]), gp[no][st]=0; } no^=1; ls^=1; } dp[x][i]=(LL)gp[no][ST-1]*C[(int)G[x].size()-(int)L.size()-(x!=1)][cnt]%MOD; } } string Hash_tree(int x, int st, int Fa) { vector<string> v; for (Vecit p=T[x].begin(); p!=T[x].end(); ++p) { if (*p!=Fa && (st>>(*p-1))&1) v.push_back(Hash_tree(*p, st, x)); } sort(v.begin(), v.end()); string res=""; for (int i=0; i<(int)v.size(); ++i) res+='1'+v[i]+'0'; return res; } inline int Hash_to_int(string s) { int res=0, le=s.length(); for (int i=0; i<le; ++i) res=(res<<1)|(s[i]=='1'); return res; } inline int Build_tree(string tree, int K) { int x=1, cnt=1, le=tree.length(); for (int i=0; i<le; ++i) if (tree[i]=='0') { x=fa[x]; if (!x) return -1; } else { fa[++cnt]=x; T[x].push_back(cnt); T[cnt].push_back(x); E.push_back(Mp(x, cnt)); x=cnt; if (x>K) return -1; } if (x!=1) { cerr << tree << endl; exit(13); } return cnt; } typedef unsigned long long ULL; map<ULL, int> Map; ULL get_hash(int n) { ULL ret=0; vector<int> v; for (int i=1; i<=n; ++i) { v.push_back(Hash_to_int(Hash_tree(i, (1<<n)-1, 0))); } sort(v.begin(),v.end()); for (int i=0; i<n; ++i) ret=ret*19260817+v[i]; return ret; } void DFS(string tree, int K) { if ((int)tree.length() < 2*(K-1)) { DFS(tree+'1', K); DFS(tree+'0', K); return; } E.clear(); for (int i=0; i<=K; ++i) T[i].clear(); if (Build_tree(tree, K) != K) return; int ss=Hash_to_int(Hash_tree(1, (1<<K)-1, 0)); if (~A[ss]) return; ULL haha=get_hash(K); A[ss]=(Map.count(haha)? Map[haha] : Map[haha]=Calc(K, K-1, ::K)); for (int st=0; st<(1<<K)-1; ++st) { string gt=Hash_tree(Last_pos(st), st, 0); if ((int)gt.length() != 2*(Count(st)-1)) continue; A[ss]=(A[ss]-A[Hash_to_int(gt)]+MOD)%MOD; } memset(pd, 0, sizeof pd); for (int i=1; i<=K; ++i) for (int j=i+1; j<=K; ++j) pd[i][j]=pd[j][i]=(Hash_tree(i, (1<<K)-1, fa[i]) == Hash_tree(j, (1<<K)-1, fa[j])); for (int i=1; i<=n; ++i) memset(dp[i], 0, sizeof(int)*(K+1));; Get_dp(1, 0, K); int res=0; for (int i=1; i<=n; ++i) Ad(res, dp[i][1]); Ad(Ans, (LL)A[ss]*res%MOD); } int main() { memset(A, -1, sizeof A); scanf("%d%d", &n, &K); for (int i=1, x, y; i<n; ++i) { scanf("%d%d", &x, &y); Add(x, y); Add(y, x); } for (int i=0; i<=n; ++i) { C[i][0]=1; for (int j=1; j<=i && j<=20; ++j) C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD; } for (int i=1; i<=K+1; ++i) DFS("", i); printf("%d\n", Ans); return 0; }View Code
相关文章推荐
- 【HDU3341】AC自动机状态压缩DP,或者说hash枚举DP,-------出题人卡常数都是狗!!!!!
- [BZOJ3214][ZJOI2013]丽洁体(Hash+DP)
- bzoj5196 [Usaco2018 Feb]Taming the Herd(dp)
- 直角三角形 纪中2543 枚举+hash
- hdu 4495 - Rectangle(hash+二分+dp)
- 【斜率DP】【bzoj 1096】: [ZJOI2007]仓库建设
- 2018网易校园招聘 DP
- SCU 4488 king's trouble II(dp||枚举)
- POJ 2018 Best Cow Fences + UVA Live 4726 Average 斜率优化DP
- hdu5965 dp枚举
- [KM 树同构Hash DP] BZOJ 3197 [Sdoi2013]assassin
- 区间Dp 暴力枚举+动态规划 Hdu1081
- bzoj1060 [ZJOI2007]时态同步 [树形dp][贪心…]
- HDU 5763 Another Meaning dp+字符串hash || DP+KMP
- HDOJ4886(hash+枚举)
- BZOJ1003: [ZJOI2006]物流运输 Spfa+DP
- POJ 1745:Divisibility 枚举某一状态的DP
- ZJOI2018 滑雪记 + 部分题解
- bzoj2817[ZJOI2012]波浪 DP+高精度
- 【BZOJ 1096】【ZJOI 2007】仓库建设 DP+斜率优化