我看了一下,网上好像没有跟我一样做法的,而且我根本学不会那个做法。那我只好发个博客啦(做法也许有错)!
题意
有
n
n
个物品和个条件,每个条件表示
i
i
的权值小于或等于的权值,每个
j
j
只会出现一次。
要求给每个物品分配一个权值,使得满足所有的条件,并且到
MAX
M
A
X
的每个值都出现了(其中
MAX
M
A
X
指最大权值)。
分析
首先
i=j
i
=
j
的条件很好搞,直接用个并查集合并就行了。
然后每个
j
j
只会出现一次,所以就可以把当做其父亲。
如果出现了环,就一定没有满足条件的方案。
那么原问题可以转化为:一棵森林,给每个点分配一个权值,使得
1、每个点的权值比父亲大;
2、
1
1
到的每个值都出现了。
为了方便,可以算每个点权值比父亲小,意义是一样的。
设
dp[i][j]
d
p
[
i
]
[
j
]
为考虑了
i
i
这棵子树,的权值不大于
j
j
时的方案数,那么不考虑2条件,那么
设 dp[0][j] d p [ 0 ] [ j ] 为考虑所有点,最大权值为 j j 时的方案数,则
接下来考虑2条件。设 f[i] f [ i ] 为最大值为 i i 并且每个值都出现了的方案数。可以得到
那么 ∑f[i] ∑ f [ i ] 就是答案了。
时间复杂度: O(n2) O ( n 2 ) 。
代码
#include<bits/stdc++.h>
using namespace std;
#define REP(i,st,ed) for(int i=(int)(st),i##end=(int)(ed);i<=i##end;++i)
#define DREP(i,st,ed) for(int i=(int)(st),i##end=(int)(ed);i>=i##end;--i)
template<typename T>bool chkmin(T &x,const T &y){return x>y?x=y,1:0;}
template<typename T>bool chkmax(T &x,const T &y){return x<y?x=y,1:0;}
#ifdef __linux__
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#endif
template<typename T>T read(){
T x=0,f=1;
char c=getchar();
while((c<'0')||(c>'9')){if(c=='-')f=-1;c=getchar();}
while((c>='0')&&(c<='9'))x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
#define read() read<int>()
template<typename T>void write(T x,char c){
static char t[25];
static int tlen;
t[tlen=1]=c;
if(x<0)putchar('-'),x=-x;
do t[++tlen]=(x%10)^48;
while(x/=10);
while(tlen)putchar(t[tlen--]);
}
#define pb push_back
typedef long long ll;
typedef double lf;
const int maxn=105,mod=1e9+7;
int n,m,tot;
int fa[maxn],id[maxn];
int C[maxn][maxn];
void add(int &x,const int &y){
x+=y;
if(x<0)x+=mod;
if(x>=mod)x-=mod;
}
void init(){
int n=100;
REP(i,0,n)
C[i][0]=1;
REP(i,1,n)
REP(j,1,n)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
int find_fa(int x){
return x==fa[x]?x:fa[x]=find_fa(fa[x]);
}
bool p[maxn][maxn],p2[maxn][maxn],indeg[maxn];
int lim,dp[maxn][maxn],f[maxn],vis_cnt;
vector<int>E[maxn];
void DFS(int u){
vis_cnt+=(u!=0);
REP(i,0,E[u].size()-1)DFS(E[u][i]);
REP(i,1,tot){
dp[u][i]=1;
REP(j,0,E[u].size()-1){
int v=E[u][j];
dp[u][i]=1ll*dp[u][i]*dp[v][i-(u>0)]%mod;
}
if(u>0)
add(dp[u][i],dp[u][i-1]);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
init();
n=read(),m=read();
REP(i,1,n)fa[i]=i;
int u,v;
char s[10];
REP(i,1,m){
scanf("%d%s%d",&u,s,&v);
if(s[0]=='=')fa[find_fa(v)]=find_fa(u);
else p[u][v]=1;
}
REP(i,1,n)
if(fa[i]==i)
id[i]=++tot;
REP(i,1,n)
if(fa[i]!=i)
id[i]=id[find_fa(i)];
REP(i,1,n)
REP(j,1,n)
if(p[i][j]){
p2[id[i]][id[j]]=1;
indeg[id[j]]=1;
}
REP(i,1,tot)
REP(j,1,tot)
if(p2[i][j])
E[i].pb(j);
REP(i,1,tot)
if(!indeg[i])
E[0].pb(i);
DFS(0);
int ans=0;
REP(i,1,tot){
f[i]=dp[0][i];
REP(j,1,i-1)
add(f[i],-1ll*f[j]*C[i][j]%mod);
add(ans,f[i]);
}
write(vis_cnt==tot?ans:0,'\n');
return 0;
}