我看了一下,網上好像沒有跟我一樣做法的,而且我根本學不會那個做法。那我只好發個部落格啦(做法也許有錯)!有n
n
個物品和
m' role="presentation" style="position: relative;">m
m個條件,每個條件表示
i i
的權值小於或等於
j' role="presentation" style="position: relative;">j
j的權值,每個
j j
只會出現一次。
要求給每個物品分配乙個權值,使得滿足所有的條件,並且
1' role="presentation" style="position: relative;">11到
max max
的每個值都出現了(其中ma
x max
指最大權值)。首先i
=ji =j
的條件很好搞,直接用個並查集合並就行了。
然後每個
j j
只會出現一次,所以就可以把
i' role="presentation" style="position: relative;">i
i當做其父親。
如果出現了環,就一定沒有滿足條件的方案。
那麼原問題可以轉化為:一棵森林,給每個點分配乙個權值,使得
1、每個點的權值比父親大; 2、1
1
到max' role="presentation" style="position: relative;">max
max的每個值都出現了。
為了方便,可以算每個點權值比父親小,意義是一樣的。 設d
p[i]
[j] dp[
i][j
]為考慮了
i i
這棵子樹,
i' role="presentation" style="position: relative;">i
i的權值不大於
j j
時的方案數,那麼不考慮2條件,那麼dp
[i][
j]=d
p[i]
[j−1
]+∏u
is a so
n of
idp[u][
j−1]
' role="presentation">dp[
i][j
]=dp
[i][
j−1]
+∏ui
saso
nofi
dp[u
][j−
1]dp
[i][
j]=d
p[i]
[j−1
]+∏u
isas
onof
idp[
u][j
−1]設
dp[0
][j]
d p[
0][j
]為考慮所有點,最大權值為
j j
時的方案數,則dp
[0][
i]=∏
u is
a rootd
p[u]
[j]' role="presentation">dp[
0][i
]=∏u
isar
ootd
p[u]
[j]d
p[0]
[i]=
∏uis
aroo
tdp[
u][j
]接下來考慮2條件。設f[
i]f [i
]為最大值為
i i
並且每個值都出現了的方案數。可以得到f[
i]=d
p[0]
[i]−
∑j=1
i−1f
[j]∗
cij' role="presentation">f[i
]=dp
[0][
i]−∑
j=1i
−1f[
j]∗c
jif[
i]=d
p[0]
[i]−
∑j=1
i−1f
[j]∗
cij那麼
∑f[i
] ∑f[
i]
就是答案了。
時間複雜度:o(
n2) o(n
2)
。
#include
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
bool chkmin(t &x,const t &y)
template
bool chkmax(t &x,const t &y)
#ifdef __linux__
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#endif
template
t read()
while((c>='0')&&(c<='9'))x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}#define read() read()
template
void write(t x,char c)
#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)
void init()
int find_fa(int x)
bool p[maxn][maxn],p2[maxn][maxn],indeg[maxn];
int lim,dp[maxn][maxn],f[maxn],vis_cnt;
vector
e[maxn];
void dfs(int u)
if(u>0)
add(dp[u][i],dp[u][i-1]);
}}int main()
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])
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)
write(vis_cnt==tot?ans:0,'\n');
return
0;}
HNOI2015 實驗比較
description input output sample input 5 4 1 2 1 3 2 4 1 5 sample output 5data constraint 首先對於給出的等於條件,我們可以直接把點合併。對於合併後的圖,我們發現要麼是環,要麼是樹,環則直接無解,樹我們可以用樹形d...
HNOI2015 實驗比較
description input output sample input 5 4 1 2 1 3 2 4 1 5 sample output 5data constraint 首先對於給出的等於條件,我們可以直接把點合併。對於合併後的圖,我們發現要麼是環,要麼是樹,環則直接無解,樹我們可以用樹形d...
HNOI2015實驗比較 題解
記得幾個月前自己曾經做過一道關於一張dag求排列的問題,現如今遇到了的是一道關於樹求排列的問題.這乙個問題看似簡單實際上有乙個細節那就是他可以取 這就使得複雜度公升高了.首先,最簡單的插孔原理。這乙個非常簡單,做這道題時,蒟蒻我現推式子。為什麼要解決這個問題呢,因為最基本的,在不考慮等於的情況下,n...