題解 2017 山東一輪集訓 Day5 蘋果樹

2022-05-01 19:39:13 字數 2551 閱讀 7899

題目傳送門

給出乙個 \(n\) 個點的圖,每個點都有乙個權值 \(f_i\) ,如果 \(f_i=-1\) 表示 \(i\) 這個點是壞的。定義乙個點是有用的當且僅當它不是壞的,並且它連的點中至少有乙個點不是壞的。問有多少種生成樹滿足有用的點的權值之和 \(\le \lim\)。

\(n\le 40\)

其實這道題目不難,只是腦子卡路了而已。。。

可以想到,我們可以先統計選出哪些點為有用點權值 \(\le lim\),我們記錄有 \(i\) 個有用點且合法的方案數為 \(\text(i)\),你發現統計有多少種生成樹滿足有 \(i\) 個有用點其實只跟 \(i\) 有關,這個可以用矩陣樹定理求出來,兩者相乘就是有 \(i\) 個有用點時產生的貢獻。

具體講一下吧,前面那個東西可以折半搜尋,就是拆成兩部分然後合起來考慮,排個序就好了。時間複雜度 \(\theta(n2^)\) 。

後面乙個關鍵就在於容斥,你發現其實恰好有 \(i\) 個有用點不是很好求,但是至多有 \(i\) 個有用點其實比較好求,具體來說,連邊的方法就是不壞但不有用的點只能連壞點,壞點可以隨便連,然後求生成樹個數。考慮至多有 \(i\) 個有用點的方案數為 \(f(i)\),恰好有 \(i\) 個有用點的方案數為 \(g(i)\),那麼可以得到關係式:

\[g(i)=f(i)-\sum_^\binomg(j)

\]正確性顯然。此部分時間複雜度瓶頸為矩陣樹定理部分,所以為 \(\theta(n^3)\) 。

#include using namespace std;

#define int register int

#define mod 1000000007

#define maxm 1050005

#define maxn 55

template inline void read (t &t)while (c >= '0' && c <= '9') t *= f;}

template inline void read (t &t,args&... args)

template inline void write (t x)if (x > 9) write (x / 10);putchar (x % 10 + '0');}

int n,m,lim,tot,cnt1,cnt2,cc[maxn],bin[maxn][maxn],cnt[maxn],sum[maxn],val[maxn];

int mul (int a,int b)

int dec (int a,int b)

int add (int a,int b)

int qkpow (int a,int b)

int inv (int x)

struct node

}c1[maxm],c2[maxm];

void dfs1 (int x,int s,int d),void ();

dfs1 (x + 1,s,d);

if (val[x] != -1) dfs1 (x + 1,s + val[x],d + 1);

}void dfs2 (int x,int s,int d),void ();

dfs2 (x + 1,s,d);

if (val[x] != -1) dfs2 (x + 1,s + val[x],d + 1);

}int mat[maxn][maxn];

void link (int x,int y)

int matrixtree (int k)

else if (i > tot) link (i,j);

else if (j > tot) link (i,j);

for (int i = 1;i <= n;++ i) for (int j = 1;j <= n;++ j) mat[i][j] = (mat[i][j] % mod + mod) % mod;

int res = 1;

for (int i = 1;i < n;++ i)

res = mul (res,mat[i][i]);

} return res;

}signed main()

for (int i = 0;i <= n;++ i) bin[i][0] = 1;

for (int i = 1;i <= n;++ i)

for (int j = 1;j <= i;++ j)

bin[i][j] = add (bin[i - 1][j - 1],bin[i - 1][j]);

for (int i = 0;i <= tot;++ i) sum[i] = matrixtree (i);

for (int i = 1;i <= tot;++ i)

for (int j = 0;j < i;++ j)

sum[i] = dec (sum[i],mul (bin[i][j],sum[j]));

int res = 0;for (int i = 0;i <= tot;++ i) res = add (res,mul (cnt[i],sum[i]));

write (res),putchar ('\n');

return 0;

}

2017 山東一輪集訓 Day4 基因

設定 sqrt 個關鍵點,維護出關鍵點到每個右端點之間的答案以及pam的左指標,每次暴力向左插入元素即可,為了去重,還需要記錄一下pam上每個節點在每個關鍵點為左端點插入到時候到最左邊出現位置,總複雜度 o n sqrt program by mangoyang pragma gcc optimiz...

2017 山東一輪集訓 Day7 逆序對

題解 滿滿的套路題。首先顯然從大到小列舉 然後每次生成的逆序對是1 i 1 的 這樣做dp是nk的 複雜度太高了 那我們轉化一下問題 變成sigma ai ai 據說是個經典問題。感覺非常奇妙 先容斥一下,也就是說 總的 至少1個條件不滿足 至少2個條件不滿足 那考慮一下如何算有x個條件不滿足 不滿...

2017 山東一輪集訓 Day6 重建

考試的時候以為兩者最短路差值的絕對值為 階梯拋物線 像這樣 可以二分,然而並沒有單峰性。不過騙了70分,混了個rank1,血賺 include.h define gt p1 p2 p2 p1 buf fread buf,1,1000000 stdin p1 p2 eof p1 define pt c...