- 對於每個循環 for(i←[j,k]),如果不考慮 j>k 的話,答案就是一個積分的式子(暴力維護每一項的係數積上去就沒了),現在就很頭疼
- 膜了題解感覺有點巧妙,考慮積分的組合意義,就是在積分區間隨便灑個點,那麼發現係數就是不同的大小關係數(相等的情況可以不用管,因爲這樣次數會減一),於是按不等關係建出圖就是這個圖的拓撲序數,狀壓 dp 即可,強連通分量必須選同一個數,要縮一下點
#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
typedef long long ll;
cs int N = 30;
int id[N]; bool mp[N][N];
void adde(int x, int y){ if(x<0||y<0) return; mp[x][y] = true; }
int n, en, e[N]; ll dp[1<<22]; char str[N];
int dfn[N], low[N], c[N], nd, tim, sta[N], in[N], top;
void dfs(int u){
dfn[u]=low[u]=++tim; sta[++top]=u; in[u]=true;
for(int i=0; i<=en; i++) if(mp[u][i]){
if(!dfn[i]) dfs(i),low[u]=min(low[u],low[i]);
else if(in[i] && dfn[i]<low[u]) low[u]=dfn[i];
} if(low[u]==dfn[u]){
do{ in[sta[top]]=0; c[sta[top]]=nd; }
while(sta[top--]!=u); ++nd;
}
}
int main(){
#ifdef FSYolanda
freopen("1.in","r",stdin);
#endif
scanf("%d",&n); id['n'-'a']=-1;
for(int i=1; i<=n; i++){
scanf("%s",str+1);
if(str[1]=='l') break;
scanf("%s",str); int c=str[0]-'a'; id[c]=en++;
scanf("%s",str);
scanf("%s",str); int len=strlen(str);
int A=0, B=0; if(str[len-2]=='1') A=-1;
else A=id[str[len-2]-'a'];
scanf("%s",str); B=id[str[0]-'a'];
adde(A,id[c]); adde(id[c],B);
} --n;
for(int i=0; i<en; i++)
for(int j=0; j<en; j++) if(!mp[i][j])
for(int k=0; k<en; k++) if(mp[i][k]&&mp[k][j]) mp[i][j]=true;
for(int i=0; i<en; i++) if(!dfn[i]) dfs(i);
for(int i=0; i<en; i++)
for(int j=0; j<en; j++) if(mp[i][j]) e[c[i]]|=(1<<c[j]);
dp[0]=1;
for(int S=0; S<(1<<nd); S++) if(dp[S])
for(int i=0; i<nd; i++) if(!(S>>i&1)&&!(S&e[i])) dp[S|(1<<i)]+=dp[S];
ll a=1; for(int i=1; i<=nd; i++) a*=i;
cout<<nd<<" "; ll g=__gcd(dp[(1<<nd)-1],a);
cout<<dp[(1<<nd)-1]/g<<"/"<<a/g<<endl;
return 0;
}