GDOI2018模擬9 14 通訊

2021-08-08 10:50:27 字數 2156 閱讀 8896

比賽沒有仔細想,碼了個n2

暴力,結果還被卡常了。

暴力思路如下:

先列舉根為x,依次加入x+1,x+2,x+3……,加入乙個點y(y>x)時,如果它的子樹中沒有已經加入的點,那麼它就會使距離增大,再暴力往上跳,給它的祖先打上標記,直到到某個點,這個點已經被打上標記就可以停止了,同時可以算出增加的距離。

感覺這個思路很想gdoi-2017-d1-t2那種,因為每個點只會被打上一次標記,所以複雜度可以保證。

然而我忽略了這種樹上和邊有關的計數類問題必須要想到一種思路:對每條邊的貢獻單獨考慮。

我們可以列舉一條邊,給這條邊分成的兩個集合的點黑白染色,再反映到1-n的序列上。

這條邊的貢獻等於n∗

(n+1

)/2−

∑s∗(

s+1)

/2,其中s是各個連續相同顏色塊的長度。

當然我們也可以隨便選擇乙個根建樹,對於每條邊,只給它的深度大的端點的子樹染色,利用線段樹就可以直接求答案了。

既然是給子樹染色,那麼樹上啟發式用可以用上了。

撤銷操作就暴力染回去。

時間複雜度:o(

nlog

nlog

n)

code:

#include

#include

#define ll long long

#define fo(i, x, y) for(int i = x; i <= y; i ++)

#define sqr(a) ((a) * (a + 1) / 2)

using namespace std;

const int n = 100005;

const ll mo = 1e9 + 7;

int n, x, y;

int final[n], tot;

struct edge e[n * 2];

int fa[n], bz[n], siz[n], son[n];

ll ans;

ll ksm(ll x, ll y)

struct tree t[n * 10];

void link(int

x, int

y) void dg(int

x) bz[x] = 0;

}void bin(int i, int l, int r)

void build(int i, int

x, int

y) int

m = (x + y) / 2;

build(i + i, x, m); build(i + i + 1, m + 1, y);

bin(i, x, y);

}void change(int i, int

x, int

y, int l, int r)

intm = (x + y) / 2;

if(l <= m) change(i + i, x, m, l, r); else change(i + i + 1, m + 1, y, l, r);

bin(i, x, y);

}void dfs(int

x) bz[x] = 0;

}void clear(int

x) bz[x] = 0;

}void dg1(int

x) if(son[x]) dg1(son[x]);

for(int i = final[x]; i; i = e[i].next)

change(1, 1, n, x, 1);

ans += (ll)n * (n + 1) / 2 - t[1].s;

if(son[fa[x]] != x) clear(x);

bz[x] = 0;

}int main()

dg(1);

build(1, 1, n);

dg1(1);

ans = ans * 2 % mo * ksm((ll)n * (n + 1) / 2, mo - 2) % mo;

printf("%lld", ans);

}

GDOI2018模擬7 8 質數

將1 n分成盡可能小的集合,使得每個集合的元素均為質數 乙個數n n 6000 第一行乙個數m表示分成幾塊 第二行n個1 m的數表示每個數分到哪一塊 2 1 2 2 1 1 1 1 2 這題很有趣 我們知道有個哥德 猜想 任意乙個足夠大的偶數可以分成兩個質數的和 由於目前人類沒有證明出它是錯的,而且...

GDOI2018模擬8 11 決戰

聽說暴力狀壓可以過?然而我常數不好只有90分 考慮普通的狀壓,f i s j 表示當前填到第i行,第i行的狀態為s,用了j個哲學 家的方案數 我們把最後一維看做多項式,用x j的係數表示答案 咦?模數是998244353哦,那我們是不是可以用ntt加速呢?如果我們求出對於所有wi 答案的多項式的點值...

GDOI2018模擬8 14 神奇的矩陣

輸出一行表示答案 3 3 2 1 2 3 4 5 6 7 8 9 真是神奇的一道題 為了避免絕對值的影響,讓每個數字從小到大加入,對於每個數字考慮貢獻 設f i j 表示以 i,j 為左上角的k k的矩陣中有數的個數 那麼乙個數在加入時,所有包括它的k k矩陣的f的和,就是這個數對答案做的正貢獻 那...