2020-10-9联赛模拟12+晚间测试5

联赛模拟12

T1 松鼠的新家

做过的原题,lca+树上差分,但要注意算重的情况,将最终\(a[2~n]\)的结果各减去一

T2 trade

\(70\)分:
看到题目第一眼想到了\(dp\)\(dp[i][j]\),但如果记录前\(i\)个买/卖了\(j\)个的最大利润,你会发现无法转移,
可以用\(dp[i][j]\)表示前i个货物处理完之后手中剩下\(j\)个的最大利润,转移就比较简单,考虑当前的第i个买还是卖还是忽略:
\(dp[i][j]=max(dp[i-1][j],max(dp[k][j-1]-a[i],dp[k][j+1]+a[i]));\)
时间\(n^3\)的,然后取个前缀\(max\)就不用枚举\(k\)了,并且发现压掉一维\(i\)也可以,所以时间\(n^2\),空间\(O(n)\)
一直想再优化,无果,\(70\)分等死
\(100\)分:
可反悔贪心,不记得以前做过这么维护的题。
用小根堆维护,当前可以卖的物品。
每扫到一个物品,若它不大于堆顶,入堆。
否则出堆顶,向堆中放入2个该物品,加上贡献\(val-top().val\)
设当前物品是\(b\),堆顶是\(a\),以后的一件物品\(c\)
第一个该物品是以后进行反悔时,\(a\)卖为\(c\)比卖为\(b\)更优,则会将\(b\)取出换为\(c\)
第二个\(b\)是又可以重新作为商品在堆里被卖;

code

if(q.empty()||x<=q.top().val) q.push((Node){i,x});
else{
      ans+=(x-q.top().val);
	q.pop();
	q.push((Node){i,x});
      	q.push((Node){i,x});
}

T3 sum

\(q\)个询问,每个询问给定n,m,求\(\sum_{i=0}^{m}C_n^i\)
重要规律:当\(m\)一定时,\(s[i]\)表示\(n=i\)的答案,则\(s[i]=s[i-1]+C_{n-1}^m\),可以结合杨辉三角来看
显然规律:n一定时,\(s[i]\)表示\(m=i\)的答案,那么可以O(1)求出\(s[i-1],s[i+1]\);
用上面两条规律可以发现\(s[n][m]\),的n和m当作左右端点可以当作莫队的板子题来做(然而我以及好多人用这两条规律水到了80)
(取模意义下除2要乘2的逆元)

T4

暴力有40
正解:
总楼盘数差分+前缀和
联通块数用\(vector\)+并查集来做,并查集每次合并的交界只会被访问一次所以复杂度正确。

晚间测试5

容易题

疫期分享题

兔子与樱花

发现如果底层节点可以合并,那么一定不会造成总结果变少(主要是考场上没造出反例……)
但是每个节点删儿子时,要从小往大删,x的每个儿子\(y\in son[x]\)贡献\((son_{cnt}[y]-1)+c[y]\),当然y每贡献一次\(c[x]\)也要改
对于每个节点开\(vector\),对儿子排序,\(dfs\)向上更新即可

code

struct Node{
	int id;
	int val;
	bool operator < (const Node &B)const{
		return val<B.val;
	}
};
vector <Node> g[maxn];
void dfs(rint x){
	if(!head[x]) return;
	for(rint i=head[x],y;i;i=e[i].next){
		y=e[i].to;
		dfs(y);
		g[x].push_back((Node){y,c[y]+son_c[y]-1});
	}
	sort(g[x].begin(),g[x].end());
	for(rint i=0,id,val;i<g[x].size();++i){
		id=g[x][i].id,val=g[x][i].val;
		if(c[x]+son_c[x]+val<=m){
			c[x]+=c[id];
			son_c[x]=son_c[x]-1+son_c[id];
			ans++;
		}
		else break;
	}
}
posted @ 2020-10-09 21:34  liuzhaoxu  阅读(76)  评论(0编辑  收藏  举报