Live2D

2020-11-27 考试总结

今天又炸了,没有什么好说的了。

T1 bins

水题,就没有什么好说的了,\(\Theta (n\log m)\) 显然。

T2 inversions

题目传送门

考试的时候被这个题区分了,主要原因是因为并没有想到一层传懒标记的话可以把一层卡成一个整体。

不难想到我们可以建出一个类似于线段树的玩意,然后每个节点的贡献就是两个子块之间的逆序对个数(其实就是归并)。

你发现翻转了之后父子关系不会变,于是我们就可以认为就是加逆序对变为了加顺序对。于是直接一开始归并的时候求一下逆序对和顺序对就好了。

时间复杂度 \(\Theta((m+2^n)n)\)

\(\texttt{Code}\)


#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define INF 0x7f7f7f7f
#define MAXN 1100005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

int n,m,th,tot,a[MAXN],s[MAXN];

#define ll long long
ll ans[2][25],get[2][MAXN << 2];

void divide (int l,int r,int dep){
	if (l >= r) return ;
	int mid = (l + r) >> 1;
	divide (l,mid,dep + 1),divide (mid + 1,r,dep + 1);
	int st1 = l,st2 = mid + 1,sam1 = 0,sam2 = 0,tot = 0;ll get1 = 0,get2 = 0;
	while (st1 <= mid || st2 <= r){
		if ((st1 <= mid && st2 <= r && a[st1] <= a[st2]) || (st1 <= mid && st2 > r)) 
		s[++ tot] = a[st1 ++],sam1 = (st1 >= l + 2 && a[st1 - 1] == s[st1 - 2]) ? sam1 + 1 : 1,get1 += (st2 - mid - 1) - (a[st1 - 1] == a[st2 - 1] ? sam2 : 0);
		else 
		s[++ tot] = a[st2 ++],sam2 = (st2 >= mid + 3 && a[st2 - 1] == a[st2 - 2]) ? sam2 + 1 : 1,get2 += (st1 - l) - (a[st1 - 1] == a[st2 - 1] ? sam1 : 0);	
	}
	ans[0][dep] += get1,ans[1][dep] += get2;
	for (Int i = l;i <= r;++ i) a[i] = s[i - l + 1];
}

signed main(){
	read (n);
	for (Int i = 1;i <= (1 << n);++ i) read (a[i]);
	divide (1,(1 << n),1);
	read (m); 
	for (Int i = 1,x;i <= m;++ i){
		read  (x);int qnow = n - x + 1;
		for (Int j = qnow;j <= n;++ j) swap (ans[0][j],ans[1][j]);
		ll ansnow = 0;for (Int j = 1;j <= n;++ j) ansnow += ans[0][j];
		write (ansnow),putchar ('\n');
	}
	return 0;
}

T3 [BalticOI 2010 Day2] Candies

题目传送门

发现 P 很好求,直接背包就好了。背包可以撤销。

考虑怎么求 Q。不难发现如果你设可行状态为 \(S\),你就是要求 \(x\) 使得 \(S\)\(S<<x\) 取并为 \(0\)。考试的时候就是这个玩意不知道怎么搞(但是 Reanp 说她一眼秒掉 Q 不知道怎么求 P,我寻思是不是搞 ACM 赛制就无敌了啊?)其实你发现不合法条件可以写成:

\[\sum_{i\in S} B_i+Q=\sum_{i\in T} B_i \]

\[\Rightarrow Q=\sum_{i\in T} B_i-\sum_{i\in S} B_i \]

然后你发现其实就是对 \(\{B_i,-B_i\}\) 做背包就好了。

时间复杂度 \(\Theta(n^2w^2/\omega)\)

T4 sheep

题目传送门

题目大意

一棵树有 \(n\) 个节点,这些节点用 \(1\)\(n\) 的整数编号。树上住着一群羊,一共有 \(k\) 只。每个节点最多可容纳一只羊住。

聪明的牧羊人意识到爱吃羊的狼迟早会学习如何爬树。为了保护羊,需要将牧羊人布置在一些节点上,使得每只羊至少有一位牧羊人去守护。

每个牧羊人仅会保护离他最近的那几只羊(如果有多个距离最近的,则全部都会保护)。羊和牧羊人之间的距离等于羊所在节点与牧羊人所在的节点之间的唯一路径上的节点数。另外,牧羊人可以与羊同在一个节点上(当然,在那种情况下,他只会保护那一只羊)。

编写程序计算牧羊人的最小数量,以便每只羊都受到至少一个牧羊人的保护。

\(n,m\le 5\times 10^5\)

思路

为什么会有人出这种不可做树上贪心啊!!!

我们设 \(d_u\) 表示点 \(u\) 到周围最近的羊的距离,这个可以 BFS 或者直接换根求出。

可以发现的是,我们如果牧羊人 \(x\) 控制羊 \(y\) ,那么 \(x\sim y\) 的路径上必须满足 \(d_i\) 严格单调递减。因为不难发现存在边 \((u,v)\),且 \(d_u>d_v\),那么 \(u\) 一定不比 \(v\) 劣。因为 \(u\) 的控制范围一定不比 \(v\) 小。

我们还可以发现的是,我们一个子树外的牧羊人其实也有可能且尽可能控制到这个子树深度最浅的羊。

于是,我们可以考虑树上贪心。每次考虑将当前节点的子树合并的时候,可以看出如果一个子树还没有合并完成,那么一定到儿子的距离都是最小且相同的。于是我们可以先考虑一个子树外的牧羊人是否可以控制这个子树深度最浅的羊,如果在 \(v\) 放一定更优,那么我们肯定就会在 \(v\) 放。否则的话我们就可以留着等祖先节点考虑。

时间复杂度 \(\Theta(n)\)

\(\texttt{Code}\)

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define INF 0x7f7f7f7f
#define MAXN 500005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

bool tag[MAXN];
vector <int> G[MAXN];
int n,k,ans,mn[MAXN],dis[MAXN];

void dfs1 (int u,int fa){for (Int v : G[u]) if (v ^ fa) dfs1 (v,u),mn[u] = min (mn[u],mn[v] + 1);}
void dfs2 (int u,int fa){for (Int v : G[u]) if (v ^ fa) mn[v] = min (mn[v],mn[u] + 1),dfs2 (v,u);}
void dfs3 (int u,int fa){
	dis[u] = -1;
	for (Int v : G[u]) if (v != fa) dfs3 (v,u),dis[u] = max (dis[u],dis[v] - 1);
	for (Int v : G[u]) if (v != fa && tag[v] && mn[v] >= mn[u]) if (dis[u] < mn[v] + 1) ans ++,dis[u] = max (dis[u],mn[v] - 1);
	if (mn[u] == 0 && dis[u] < 0) tag[u] = 1;
	for (Int v : G[u]) if (v != fa && tag[v] && mn[v] < mn[u]) if (dis[u] < mn[v] + 1) tag[u] = 1; 
}

signed main(){
	read (n),read (k);
	for (Int i = 2,u,v;i <= n;++ i) read (u),read (v),G[u].push_back (v),G[v].push_back (u);
	for (Int i = 1;i <= n;++ i) mn[i] = n + 1;
	for (Int i = 1,u;i <= k;++ i) read (u),mn[u] = 0;
	dfs1 (1,0),dfs2 (1,0),dfs3 (1,0);
	write (ans + tag[1]),putchar ('\n'); 
	return 0;
}
posted @ 2020-11-27 18:38  Dark_Romance  阅读(79)  评论(0编辑  收藏  举报