【省選模擬】20/04/20 Fygon(建圖)(狀壓DP)

  • 對於每個循環 for(i[j,k])for(i\leftarrow [j,k]),如果不考慮 j>kj>k 的話,答案就是一個積分的式子(暴力維護每一項的係數積上去就沒了),現在就很頭疼
  • 膜了題解感覺有點巧妙,考慮積分的組合意義,就是在積分區間隨便灑個點,那麼發現係數就是不同的大小關係數(相等的情況可以不用管,因爲這樣次數會減一),於是按不等關係建出圖就是這個圖的拓撲序數,狀壓 dpdp 即可,強連通分量必須選同一個數,要縮一下點
#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; 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章