• P7024 [NWRRC2017]Fygon 2.0


    膜拜 ( ext{hehezhou})

    题解

    你发现相当于是给这 (m) 个变量进行染色,每一个循环语句相当于是一个大小的限制比如说 (jle ile k) 之类的,然后问你染色的方案数。

    我们可以对于一个 (ile j) ,我们可以建一条有向边 (i->j) ,表示在遍历这张图的时候 (i) 需要出现在 (j) 的前面,然后发现对于其中的强连通分量,他必须是全部相同的,你就直接缩点即可,然后剩下的就是一个 (DAG)

    然后就变成了 (DAG) 上的染色方案数,这个东西好像可以状压,具体明天在想吧,我困了


    由于我们考虑的是渐进复杂度,所以虽然对于一个限制 (ile j) 存在 (i=j) 的情况,我们可以不用考虑,因为他在其中所占的比例过于小,相对于极限来说。于是题目就变成了一张 (DAG)(top) 序数量。(我在想是不是考虑了就错了?不是很明白。。。)

    我们考虑状压 (dp) ,设 (f_i) 表示在已经访问过的点的状态为 (i) 的时候,其 (top) 序数量是多少。然后拿头硬转移就可以了吧。

    代码如下

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=25;
    int n=0,m;char s[N];
    int id[256];
    struct Graph{
    	struct Edge{int nxt,from,to;}e[N<<1];int fir[N],size=0;
    	void add(int u,int v){e[++size]=(Edge){fir[u],u,v},fir[u]=size;}
    }g1,g2;
    int bel[N],tot=0;
    int dfn[N],low[N],cnt=0;
    stack<int> h;bool vis[N];
    void tarjan(int u){
    	dfn[u]=low[u]=++cnt;
    	vis[u]=true,h.push(u);
    	for(int i=g1.fir[u];i;i=g1.e[i].nxt){
    		if(!dfn[g1.e[i].to]){
    			tarjan(g1.e[i].to);
    			low[u]=min(low[u],low[g1.e[i].to]);
    		}
    		else if(vis[g1.e[i].to]) low[u]=min(low[u],dfn[g1.e[i].to]);
    	}
    	if(dfn[u]==low[u]){
    		++tot;
    		while(h.top()!=u)
    		vis[h.top()]=false,bel[h.top()]=tot,h.pop();
    		vis[h.top()]=false,bel[h.top()]=tot,h.pop();
    	}
    }
    int f[1<<N],deg[N];
    int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
    signed main(){
    	cin>>m;
    	for(int i=1;i<m;++i){
    		scanf("%s",s+1),scanf("%s",s+1),id[(int)s[1]]=++n;
    		scanf("%s",s+1),scanf("%s",s+1);
    		if('a'<=s[7]&&s[7]<='z') g1.add(id[(int)s[7]],n);
    		scanf("%s",s+1);
    		if('a'<=s[1]&&s[1]<='z'&&s[1]!='n') g1.add(n,id[(int)s[1]]);
    	}
    	scanf("%s",s+1);
    	for(int i=1;i<=n;++i){
    		if(dfn[i]) continue;
    		tarjan(i);
    	}
    	for(int i=1;i<=g1.size;++i){
    		if(bel[g1.e[i].from]!=bel[g1.e[i].to]){
    			g2.add(bel[g1.e[i].to],bel[g1.e[i].from]);
    		}
    	}
    	printf("%lld ",tot);
    	f[0]=1;
    	for(int now=0;now<(1<<tot);++now){
    		for(int i=1;i<=tot;++i){
    			if(now&(1<<(i-1))) continue;
    			bool flag=true;
    			for(int j=g2.fir[i];j;j=g2.e[j].nxt){
    				flag&=(bool)(now&(1<<(g2.e[j].to-1)));
    			}
    			if(!flag) continue;
    			// printf("%lld %lld %lld %lld
    ",now,i,now|(1<<(i-1)),f[now]);
    			f[now|(1<<(i-1))]+=f[now];
    		}
    	}
    	int tmp,res=1;
    	for(int i=1;i<=tot;++i) res*=i;
    	tmp=gcd(res,f[(1<<tot)-1]);
    	printf("%lld/%lld
    ",f[(1<<tot)-1]/tmp,res/tmp);
    	return 0;
    }
    
  • 相关阅读:
    MongoDB 安装和即基本操作
    技术型创业者easy遇到的三大问题
    Swoole源代码学习记录(十五)——Timer模块分析
    利用NSInvocation对方法进行抽象,实现对方法的加锁
    Atitit.hibernate体系结构大总结
    HDU
    程序猿工作效率的影响因素和管理者怎样推断
    Linux下tomcat使用
    [1204 寻找子串位置] 解题报告
    Team Foundation Server 2013 with Update 3 Install LOG
  • 原文地址:https://www.cnblogs.com/Point-King/p/14232305.html
Copyright © 2020-2023  润新知