20240726模拟赛订正题笔记

(T1)lnsyoj2212 刷数组

考场上切掉了,所以来说说考场上的做法。
首先看数据范围,线段树并不能拿满分,所以考虑在数组上操作。
如何处理区间覆盖:记录一下区间覆盖的数,然后记录第几次覆盖,单点修改或增加时查看次数被覆盖了几次,若与正常覆盖次数不符,则将此数设为新的覆盖数。
考场代码如下:

#include <cstdio>
#define int long
using namespace std;
int ans;
int a[10000005];
int qtcs[10000005];
int qtshu;
int yqtcs;
int n,q;
signed main(){
	scanf("%ld%ld",&n,&q);
	for(int i=1;i<=q;i++){
		int opt;
		scanf("%ld",&opt);
		if(opt==1){
			int x,y;
			scanf("%ld%ld",&x,&y);
			if(qtcs[x]<yqtcs){
				a[x]=qtshu;
				qtcs[x]=yqtcs;
			}
			ans+=y-a[x];
			a[x]=y;
		}
		else if(opt==2){
			int x,y;
			scanf("%ld%ld",&x,&y);
			if(qtcs[x]<yqtcs){
				a[x]=qtshu;
				qtcs[x]=yqtcs;
			}
			ans+=y;
			a[x]+=y;
		}
		else if(opt==3){
			int y;
			scanf("%ld",&y);
			qtshu=y;
			ans=y*n;
			yqtcs++;
		}
		printf("%ld\n",ans); 
	}
	return 0;
}

(T2)lnsyoj2213 LCA 的统计

(考场上还想以为有规律呢,最后提交时还忘了记忆化,真是服了)
首先设\(f_{i}\)为当根节点的权值为i时所有LCA的和,\(g_{i}\)为当根节点的权值为i时树的节点数。
转移为:\(f_{i}=\begin{cases}2f_{i/2}+i(g_{i}^{2}-2g_{i/2}^2)&i\%2==0\\f_{i/2}+f_{i/2+1}+i(g_{i}^{2}-g_{i/2}^2-g_{i/2+1}^2)&i\%2==1\end{cases}\)
\(g_{i}=\begin{cases}2g_{i/2}+1&i\%2==0\\g_{i/2}+g_{i/2+1}+1&i\%2==1\end{cases}\)
可以通过打表找规律得知\(g_{i}=2i-1\)
原因:因为一个根节点为i的树的左右子树都为神奇的树,所以肯定将左右两个树的权值进行合并,然后需要考虑一下几种情况:
1.左子树与根节点的LCA总和,因为左子树与根节点的LCA一定为根节点,所以权值都采用根节点的。
2.右子树与根节点的LCA总和,与左子树相似。
3.左子树与右子树的LCA总和,因为左子树与右子树的LCA显然为根节点,所以权值都采用根节点的。
4.根节点与根节点的LCA总和,直接加一吧。
所以会发现除了左右子树内的贡献不采用根节点,其余的均采用根节点的权值。
dp时进行记忆化搜索,记忆化时用map或unordered_map维护,时间复杂度\(O(Tlog_{n})\),取模细节超级多,说不定哪就挂了。。。。。。
代码如下:

#include <cstdio>
#include <algorithm>
#include <unordered_map>
#define int long long
#define mod 1000000007
using namespace std;
unordered_map<int,int> um;
inline int g(int i){
	return (2*i%mod-1+mod)%mod;
}
int dfs1(int i){
	if(um[i]!=0){
		return um[i];
	}
	if(i&1){
		um[i]=((dfs1(i/2+1)+dfs1(i/2))%mod+i%mod*(((g(i)*g(i)%mod-g(i/2+1)*g(i/2+1)%mod+mod)%mod-g(i/2)*g(i/2)%mod+mod)%mod)%mod)%mod;
		return um[i];
	}
	else{
		um[i]=((dfs1(i/2)*2)%mod+i%mod*(((g(i)*g(i)%mod-g(i/2)*g(i/2)%mod+mod)%mod-g(i/2)*g(i/2)%mod+mod)%mod)%mod)%mod;
		return um[i];
	}
}
int T;
signed main(){
	um[1]=1;
	scanf("%lld",&T);
	for(int i=1;i<=T;i++){
		int n;
		scanf("%lld",&n);
		printf("%lld\n",dfs1(n));
	}
	return 0;
}

(T3)lnsyoj2214 设置

对于此问,只需要将最少效果值的k的解求出,再异或即可,具体如下:
首先将每个零件的所有设置的效果值从小到大排序,时间复杂度\(O(nmlogm)\)
再将所有零件按照多关键字(第i个设置效果值与第i-1个设置效果值的差)进行从小到大排序,时间复杂度\(O(nmlogn)\)
显然1,1,1,......是最优解,[2,1,1,......]是次优解。
然后可以用小根堆(堆按照所存状态的和进行排序)进行维护,先将[2,1,1,......]状态(可以开个结构体维护:1.该状态的权值和(\(val\))2.上个状态修改了的零件到该状态的零件编号(\(lb\))3.上个状态修改某个零件到该状态后该零件的设置编号(\(zb\)))放入堆中,然后每次操作时考虑该状态修改哪个零件可以使新状态只次一点
1.当\(zb<m\)时,可以将\(lb\)号零件设置为编号为\(zb+1\)号的设置。
2.当\(lb<n\)时,可以将\(lb+1\)号零件设置为编号为\(2\)号的设置。
3.当\(lb<n\)\(zb=2\)时,可以将\(lb\)号零件设置为编号为\(1\)号的设置,并将\(lb+1\)号零件设置为编号为\(2\)号的设置。
取k堆顶然后异或起来即可。
代码如下:

#include <cstdio>
#include <queue>
#include <algorithm>
#include <vector>
#define int long long
using namespace std;
int n,m,k;
vector<int> yj[300005];
int px[300005];
bool cmp1(int a,int b){
	return a<b;
}
bool cmp2(vector<int> a,vector<int> b){
	for(int i=2;i<m;i++){
		if(a[i]-a[i-1]==b[i]-b[i-1]){
			continue;
		}
		return a[i]-a[i-1]<b[i]-b[i-1];
	}
	return a[m]-a[m-1]<b[m]-b[m-1];
}
priority_queue<pair<int,pair<int,int> >,vector<pair<int,pair<int,int> > >,greater<pair<int,pair<int,int> > > > pq;
int ans;
signed main(){
	scanf("%lld%lld%lld",&n,&m,&k);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%lld",&px[j]);
		}
		sort(px+1,px+m+1,cmp1);
		yj[i].push_back(0);
		for(int j=1;j<=m;j++){
			yj[i].push_back(px[j]);
		}
	}
	sort(yj+1,yj+n+1,cmp2);
	int val=0;
	for(int i=1;i<=n;i++){
		val+=yj[i][1];
	}
	ans=val;
	//printf("ans:%lld\n",val);
	if(k==1){
		printf("%lld\n",ans);
		return 0;
	}
	val=val-yj[1][1]+yj[1][2];
	pq.push({val,{1,2}});
	for(int i=2;i<=k;i++){
		pair<int,pair<int,int> > tmp=pq.top();
		//printf("ans:%lld\n",tmp.first);
		pq.pop();
		ans^=tmp.first;
		if(tmp.second.first<n){
			pq.push({tmp.first-yj[tmp.second.first+1][1]+yj[tmp.second.first+1][2],\
					{tmp.second.first+1,2}});
		}
		if(tmp.second.first<n && tmp.second.second==2){
			pq.push({tmp.first-yj[tmp.second.first][2]+yj[tmp.second.first][1]-yj[tmp.second.first+1][1]+yj[tmp.second.first+1][2],\
					{tmp.second.first+1,2}});
		}
		if(tmp.second.second<m){
			pq.push({tmp.first-yj[tmp.second.first][tmp.second.second]+yj[tmp.second.first][tmp.second.second+1],\
					{tmp.second.first,tmp.second.second+1}});
		}
	}
	printf("%lld\n",ans); 
}
/*
3 2 4
3 5 
5 5 
5 4 
*/
posted on 2024-07-26 16:12  jisuheng123  阅读(37)  评论(0编辑  收藏  举报