zoukankan      html  css  js  c++  java
  • 【日常训练】【CF】20200605_旅行_图论/树形dp

    题面

    题解

    现场得分:40/100

    一个接在环上的树上面统计答案的时候,我没有讨论清楚,出了点小事。

    下发题解

    另外的补充

    • 关于把环扔掉:我认为这个东西还是用拓扑来搞比较好,代码又短又好写。只用每回把度数为一的弄出来就好了。
    • 关于树上统计:如果是全都取满的,那么就是比较经典的树形dp问题。如果是有东西还能取,但是不取了,我们可以枚举根,强制令根不取,计算有多少种,最后每种取的个数的方案数除以这种方案下未取的点的个数就行了。
    • 关于树上统计的优化:我们可以用换根dp,就能做(O(n^2))了。wyj的题解

    代码

    #include<bits/stdc++.h>
    #define LL long long
    #define MAXN 210
    #define MOD 1000000009
    using namespace std;
    template<typename T>void Read(T &cn)
    {
    	char c; int sig = 1;
    	while(!isdigit(c = getchar())) if(c == '-') sig = -1; cn = c-48;
    	while(isdigit(c = getchar())) cn = cn*10+c-48; cn*=sig;
    }
    template<typename T>void Write(T cn)
    {
    	if(cn < 0) {putchar('-'); cn = 0-cn; }
    	int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
    	while(cn) wei++, cm = cm*10+cn%10, cn/=10;
    	while(wei--) putchar(cm%10+48), cm /= 10;
    	putchar(cx+48);
    }
    template<typename T>void Max(T &cn, T cm) {cn = cn < cm ? cm : cn; }
    template<typename T>void Min(T &cn, T cm) {cn = cn < cm ? cn : cm; }
    int n, m;
    int t[MAXN+1][MAXN+1];
    namespace Sub1{
    	int pan() {return n <= 20; }
    	int f[1<<20];
    	int you[MAXN+1];
    	int ans[MAXN+1];
    	int suan(int cn)
    	{
    		if(f[cn] != -1) return f[cn];
    		f[cn] = 0; 
    		for(int i = 1;i<=n;i++) you[i] = (cn & (1<<(i-1)))!=0;
    		for(int i = 1;i<=n;i++) if(you[i])
    		{
    			int ge = 0;
    			for(int j = 1;j<=n;j++) if(!you[j]) ge += t[i][j];
    			if(ge >= 2) return f[cn];
    		} 
    		for(int i = 1;i<=n;i++) if(you[i]) f[cn] = (f[cn] + suan(cn^(1<<(i-1))))%MOD;
    		int ge = 0;
    		for(int i = 1;i<=n;i++) ge += you[i];
    		ans[ge] = (ans[ge] + f[cn])%MOD;
    		return f[cn];
    	}
    	int main()
    	{
    		for(int i = 0;i<(1<<n);i++) f[i] = -1;
    		memset(ans,0,sizeof(ans));
    		f[0] = 1; ans[0]++;
    		for(int i = 1;i<(1<<n);i++) if(f[i] == -1) suan(i);
    		for(int i = 0;i<=n;i++) Write(ans[i]), puts(""); 
    		return 0;
    	}
    };
    namespace Sub2{
    	int pan() {return 1; }
    	struct qwe{
    		int a,b,ne;
    		void mk(int cn, int cm, int cx) {a = cn; b = cm; ne = cx; }
    	};
    	qwe a[MAXN*MAXN+1];
    	int alen;
    	int head[MAXN+1];
    	int du[MAXN+1], vis[MAXN+1], you[MAXN+1];
    	int dui[MAXN+1], l, r;
    	int jie[MAXN+1], nij[MAXN+1];
    	int zhan[MAXN+1], zlen;
    	int da[MAXN+1], dao[MAXN+1];
    	int f[MAXN+1][MAXN+1];
    	int ans1[MAXN+1], ans2[MAXN+1], ans3[MAXN+1];
    	int Eshu;
    	LL ksm(LL cn, LL cm) {LL ans = 1; while(cm) ans = ans*(1+(cn-1)*(cm&1))%MOD, cn = cn*cn%MOD, cm>>=1; return ans; }
    	LL zuhe(int cn, int cm) {return 1ll*jie[cn]*nij[cm]%MOD*nij[cn-cm]%MOD; }
    	void lian(int cn, int cm) {a[++alen].mk(cn, cm, head[cn]); head[cn] = alen; }
    	void yuchu(int cn)
    	{
    		jie[0] = 1;
    		for(int i = 1;i<=cn;i++) jie[i] = 1ll*jie[i-1]*i%MOD;
    		nij[cn] = ksm(jie[cn], MOD-2);
    		for(int i = cn-1;i>=0;i--) nij[i] = 1ll*nij[i+1]*(i+1)%MOD;
    	}
    	void dfs_z(int cn, int fa)
    	{
    		zhan[++zlen] = cn;
    		you[cn] = 1;
    		for(int i = head[cn];i;i = a[i].ne) 
    		{
    			int y = a[i].b;
    			if(!vis[y]) dao[cn] = 0;
    			if(y == fa || !vis[y]) continue;
    			dfs_z(y, cn); 
    		}
    	}
    	void dfs1(int cn, int fa)
    	{
    		dao[cn] = 1;
    		for(int i = head[cn];i;i = a[i].ne) 
    		{
    			int y = a[i].b;
    			if(!vis[y]) dao[cn] = -1;
    			if(y == fa || !vis[y]) continue;
    			dfs1(y, cn); if(dao[y] != 1 && dao[cn] != -1) dao[cn] = 0;
    		}
    		da[cn] = (dao[cn] == 1);
    		for(int i = head[cn];i;i = a[i].ne)
    		{
    			int y = a[i].b;
    			if(y == fa || !vis[y]) continue;
    			da[cn] += da[y];
    		}
    	}
    	void dfs2(int cn, int fa)
    	{
    		if(!fa) for(int i = 0;i<=zlen;i++) f[cn][i] = 0;
    		else for(int i = 0;i<=da[cn];i++) f[cn][i] = 0;
    		f[cn][0] = 1; int lei = 0;
    		for(int i = head[cn];i;i = a[i].ne)
    		{
    			int y = a[i].b;
    			if(y == fa || !vis[y]) continue;
    			dfs2(y, cn);
    			for(int j = 0;j<=lei+da[y];j++) ans3[j] = 0;
    			for(int j = 0;j<=lei;j++) for(int k = 0;k<=da[y];k++) ans3[j+k] = (ans3[j+k] + 1ll*f[cn][j]*f[y][k]%MOD*zuhe(j+k,j))%MOD;
    			lei += da[y];
    			for(int j = 0;j<=lei;j++) f[cn][j] = ans3[j];
    		}
    		if(dao[cn] == 1) f[cn][da[cn]] = f[cn][da[cn]-1];
    		if(dao[cn] == -1 && !fa) f[cn][zlen] = f[cn][zlen-1];
    	}
    	int main()
    	{
    		alen = 0; memset(head,0,sizeof(head)); memset(du,0,sizeof(du));
    		for(int i = 1;i<=n;i++) for(int j = 1;j<=n;j++) if(t[i][j]) lian(i,j), du[i]++;
    	
    		l = r = 0; Eshu = 0;
    		memset(vis,0,sizeof(vis));
    		for(int i = 1;i<=n;i++) if(du[i] <= 1) dui[++r] = i, vis[i] = 1;
    		while(l < r)
    		{
    			int dang = dui[++l];
    			for(int i = head[dang];i;i = a[i].ne)
    			{
    				int y = a[i].b;
    				if(vis[y]) continue;
    				du[y]--;
    				if(du[y] == 1) dui[++r] = y, vis[y] = 1;
    			}
    		}
    		
    		if(r == 0) {
    			puts("1");
    			for(int i = 1;i<=n;i++) puts("0");
    			return 0;
    		}
    		yuchu(r); memset(you,0,sizeof(you));
    		memset(ans1, 0, sizeof(ans1)); ans1[0] = 1;
    		for(int i = 1;i<=n;i++) if(vis[i] && !you[i]) 
    		{
    			zlen = 0; dfs_z(i, 0);
    			memset(ans2, 0, sizeof(ans2));
    			for(int j = 1;j<=zlen;j++)
    			{
    				dfs1(zhan[j], 0); dfs2(zhan[j], 0);
    				for(int k = 0;k<=zlen;k++) ans2[k] = (ans2[k] + f[zhan[j]][k])%MOD;
    			}
    			for(int j = 0;j<zlen;j++) ans2[j] = 1ll*ans2[j]*ksm(zlen-j, MOD-2)%MOD;
    			for(int j = 0;j<=n;j++) ans3[j] = 0;
    			for(int j = 0;j<=n;j++) for(int k = 0;k<=zlen;k++) ans3[j+k] = (ans3[j+k] + 1ll*ans1[j]*ans2[k]%MOD*zuhe(j+k,j))%MOD;
    			for(int j = 0;j<=n;j++) ans1[j] = ans3[j];
    		}
    		for(int i = 0;i<=n;i++) Write(ans1[i]), puts("");
    		return 0;
    	}
    };
    int main()
    {
    //	freopen("travel.in","r",stdin);
    //	freopen("travel.out","w",stdout);
    	Read(n); Read(m);
    	for(int i = 1;i<=n;i++) for(int j = 1;j<=n;j++) t[i][j] = 0;
    	for(int i = 1;i<=m;i++) {int bx,by; Read(bx); Read(by); t[bx][by] = t[by][bx] = 1; }
    //	if(Sub1::pan()) return Sub1::main();
    	if(Sub2::pan()) return Sub2::main();
    	return 0;
    }
    
  • 相关阅读:
    java (取文本中间)字符串之间的文本
    Mysql数据库中text还是不够
    java读取网页内容
    controller to controller
    农历类
    java.lang.RuntimeException: com.google.inject.CreationException: Unable to create injector, see the following errors
    Java中List集合去除重复数据的方法
    idea启动tomcat的中文乱码问题
    idea局域网调试 can accept external connection不可勾选
    Mysql JDBC Url参数说明useUnicode=true&characterEncoding=UTF-8
  • 原文地址:https://www.cnblogs.com/czyarl/p/13051325.html
Copyright © 2011-2022 走看看