膜拜 ( 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;
}