2025.8.11 CSP-S模拟赛33

获得了极其惨烈的40分

T1 机器人

简单dfs,不知道考场上为什么死活调不出来,以至于极大影响了心态,这确实是我的严重失误,后面忘了;

一个坐标有走过,没有走过两种状态,没有走过又分有障碍和没障碍两种情况,注意细节即可;

#include<bits/stdc++.h>
using namespace std;
int n;char c[25];
struct node{
	int x,y;
};
bool cmp(node a,node b){
	return (a.x^b.x?a.x<b.x:a.y<b.y);
}
vector<node> ans;
int flag[105][105],za[105][105];
int jz[105][105];
void dfs(int xb,int x,int y){
	if(xb>n){
		if(!jz[x][y])
			ans.push_back(node{x-50,y-50});
		jz[x][y]=1;
		return ;
	}
	flag[x][y]=1;
	int nx=x,ny=y;
	if(c[xb]=='L') nx--;
	if(c[xb]=='R') nx++;
	if(c[xb]=='D') ny--;
	if(c[xb]=='U') ny++;
	if(flag[nx][ny]!=1){
		int lst=flag[nx][ny];
		flag[nx][ny]=2;
		dfs(xb+1,x,y);
		flag[nx][ny]=lst;
	}
	if(flag[nx][ny]!=2){
		int lst=flag[nx][ny];
		flag[nx][ny]=1;
		dfs(xb+1,nx,ny);
		flag[nx][ny]=lst;
	} 
	return ;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>c[i];
	dfs(1,50,50);
	cout<<ans.size()<<"\n";
	sort(ans.begin(),ans.end(),cmp);
	for(int i=0;i<ans.size();i++){
		cout<<ans[i].x<<" "<<ans[i].y<<"\n";
	} 
	return 0;
}

T2 旅行

第一次接触基环树,考场上没有什么思路,体现出知识点的重要性;

我们发现每次更改一条边时,真正改变的答案数量时极其有限的,我们假设把一条边的颜色由 \(a\) 更改为 \(b\) ,如果这条边两端的节点均连接一条除此边之外的颜色为 \(x\) 的边,称这条边两头都有颜色 \(x\),反之同理;

我们可以发现:
1、这条边两头都有 \(a\) ,就把原来的一个联通块断成两个,那么 \(ans+=1\)
2、这条边两头都没有 \(a\) ,就减少了自己这个颜色为 \(a\) 的联通块,那么 \(ans-=1\)
3、这条边两头都有 \(b\) ,就把原来的两个联通块连成一个,那么 \(ans-=1\)
4、这条边两头都没有 \(b\) ,就增加了自己这个颜色为 \(b\) 的联通块,那么 \(ans+=1\)

因为是基环树,所以要特殊处理环上的边;如果环上除了这条边以外颜色均为 \(a\) ,那么可以忽略第一、第二条;同样的,如果环上除了这条边以外颜色均为 \(b\) ,那么可以忽略第三、第四条,证明都是显然的 ;

对于基环树找环,可以看dzb大佬的博客,写的非常好;

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
const unsigned long long p=13331;
int T,n,m,ans;
int d[MAXN],cnt[MAXN];
int fa[MAXN],dep[MAXN],lst[MAXN];
struct nd{
	int pos,col,id;
};
vector<nd> e[MAXN];
map<int,int> mp[MAXN];
struct node{
	int x,y,col;
}eg[MAXN<<1];
void dfs(int x,int lst,int col){
	cnt[x]++;
	if(cnt[x]>d[x]) return ;
	for(int i=0;i<e[x].size();i++){
		int y=e[x][i].pos;
		if(y==lst) continue;
		if(e[x][i].col==col){
			ans--;
			dfs(y,x,col);
		}
		else{
			dfs(y,x,e[x][i].col);
		} 
	}
	return ;
}
int flag[MAXN],ins[MAXN],mark[MAXN],stk[MAXN],vis[MAXN],top;
int rt;
int find(int x){
	return (x==fa[x]?x:fa[x]=find(fa[x]));
}
void add(int x,int y){
	x=find(x),y=find(y);
	if(x!=y){
		fa[y]=x;
		ans--;
	}
}
void dfs_tr(int x,int fa){
	if(ins[x]){
		rt=x;
		int v;
		mark[x]=1;
		while(stk[top]!=x){
			mark[stk[top]]=1;
			top--;
		}
		return ;
	}
	if(vis[x]==1) return ;
	stk[++top]=x;
	vis[x]=ins[x]=1;
	for(int i=0;i<e[x].size();i++){
		int y=e[x][i].pos;
		if(y==fa) continue;
		dfs_tr(y,x);
	}
	top--;
	ins[x]=0;
	return ;
} 
void dfs_eg(int x,int fa){
	if(x==rt) return ;
	for(int i=0;i<e[x].size();i++){
		int y=e[x][i].pos;
		if(y==fa) continue;
		if(mark[y]){
			flag[e[x][i].id]=1;
			dfs_eg(y,x);
		}
	} 
	return ;
}
map<int,int> bh[MAXN];
map<int,int> t;
int len;
int main(){
//	freopen("tour1.in","r",stdin);
//	freopen("tour.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>T;
	while(T--){
		cin>>n>>m;ans=n;top=0;
		for(int i=1;i<=n;i++){
			int x,y,z;cin>>x>>y>>z;
			bh[x][y]=bh[y][x]=i;
			e[x].push_back((nd){y,z,i});
			e[y].push_back((nd){x,z,i});
			mp[x][z]++,mp[y][z]++;
			eg[i].x=x,eg[i].y=y,eg[i].col=z;
		}
		for(int i=1;i<=n;i++){
			fa[i]=i;
		}
		for(int x=1;x<=n;x++){
			for(int j=0;j<e[x].size();j++){
				lst[e[x][j].col]=0;
			}
			for(int j=0;j<e[x].size();j++){
				if(lst[e[x][j].col]) add(lst[e[x][j].col],e[x][j].id);
				lst[e[x][j].col]=e[x][j].id;
			}
		}
//		cout<<"ans: "<<ans<<"\n";
		dfs_tr(1,0);
//		for(int i=1;i<=n;i++) if(mark[i]) cout<<i<<" ";
//		cout<<"\n";
		for(int i=1;i<=n;i++) t[i]=0;
		for(int i=0;i<e[rt].size();i++){
			if(mark[e[rt][i].pos]){
				flag[e[rt][i].id]=1;
				dfs_eg(e[rt][i].pos,rt);
				break;
			}
		} 
		len=0;
//		for(int i=1;i<=n;i++) if(mark[i]) cout<<i<<"\n";
		for(int i=1;i<=n;i++){
			if(flag[i]) t[eg[i].col]++,len++;
//			cout<<i<<": "<<flag[i]<<"\n";
		}
//		cout<<"len: "<<len<<"\n";
		for(int i=1;i<=m;i++){
			int x,y,z;cin>>x>>y>>z;
			int _id=bh[x][y];
			mp[x][eg[_id].col]--,mp[y][eg[_id].col]--;
			if(flag[_id]) t[eg[_id].col]--;
			if(!flag[_id]||(flag[_id]&&t[eg[_id].col]<len-1)){
				if(mp[x][eg[_id].col]>0&&mp[y][eg[_id].col]>0)  ans+=1;
				if(mp[x][eg[_id].col]==0&&mp[y][eg[_id].col]==0) ans-=1;
			}
			if(!flag[_id]||(flag[_id]&&t[z]<len-1)){
				if(mp[x][z]>0&&mp[y][z]>0) ans-=1;
				if(!mp[x][z]&&!mp[y][z]) ans+=1;
			}
			if(flag[_id]) t[z]++;
			mp[x][z]++,mp[y][z]++;
			eg[_id].col=z;
			cout<<ans<<"\n";
		}
		for(int i=1;i<=n;i++) bh[i].clear(),mp[i].clear(),e[i].clear();
		for(int i=1;i<=n;i++) flag[i]=ins[i]=vis[i]=mark[i]=0;
	}
	return 0; 
}

T3 点餐

依旧是没有学过的,正解是可持久化线段树,为此去打了板子,不过感觉还是没有理解透彻;

我们将菜品按 \(b\) 从小到大排序,然后枚举 \(x\) 作为断点,那么 \(b_X\) 必然为最大的 \(b\) ,问题就变成了在前 \(x-1\) 个菜品中寻找 \(k-1\)\(a_i\) 和最小的,这一过程可以用可持久化线段树维护前缀最小值,记为 \(w(k,x)\)

对于两个不同的决策 \(x,y(x<y)\) ,若 \(w(k,y) \leq w(k,x)\) 那么随着 \(k\) 的增加,因为 \(y\) 的选择范围严格包含了 \(x\) 的选择范围,所以 \(y\) 的新方案一定不会劣于 \(x\) 的新方案,因此可以证明具有决策单调性,可以分治求解;

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=2e5+10;
int n,lsh[MAXN],t[MAXN],tot;
int root[MAXN];
int ans[MAXN];
struct node{
	int a,b;
}p[MAXN];
bool cmp(node a,node b){
	return (a.b^b.b?a.b<b.b:a.a<b.a);
}
struct zx_tree{
	int lc,rc,sum,siz;
}tr[MAXN<<5];
void build(int &id,int l,int r){
	id=++tot;
	tr[id].siz=1;
	if(l==r) return ;
	int mid=l+r>>1;
	build(tr[id].lc,l,mid);
	build(tr[id].rc,mid+1,r);
	tr[id].siz=tr[tr[id].lc].siz+tr[tr[id].rc].siz+1;
	return ;
}
void add(int id,int &k,int l,int r,int val){
	k=++tot;
	if(l==r){
		tr[k].sum=lsh[val],tr[k].siz=1;
		return ;
	}
	int mid=l+r>>1;
	if(val<=mid){
		tr[k].rc=tr[id].rc;
		add(tr[id].lc,tr[k].lc,l,mid,val);
	}
	else{
		tr[k].lc=tr[id].lc;
		add(tr[id].rc,tr[k].rc,mid+1,r,val);
	}
	tr[k].siz=tr[tr[k].lc].siz+tr[tr[k].rc].siz;
	tr[k].sum=tr[tr[k].lc].sum+tr[tr[k].rc].sum;
	return ;
}
int query(int id,int l,int r,int val){
	if(!id||!val) return 0;
	if(tr[id].siz==val) return tr[id].sum;
	int mid=l+r>>1;
	if(val<=tr[tr[id].lc].siz) return query(tr[id].lc,l,mid,val);
	else return tr[tr[id].lc].sum+query(tr[id].rc,mid+1,r,val-tr[tr[id].lc].siz);
}
void solve(int L,int R,int l,int r){
	if(L>R) return ;
	int mid=L+R>>1;
	int &res=ans[mid]=1e18,px=-1;
	for(int i=max(l,mid);i<=r;i++){
		int q=query(root[i-1],1,n,mid-1)+lsh[p[i].a]+p[i].b;
		if(q<res){
			res=q,px=i;
		}
	}
	solve(L,mid-1,l,px);
	solve(mid+1,R,px,r);
	return ;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>p[i].a>>p[i].b;
		lsh[i]=p[i].a;
	} 
	sort(lsh+1,lsh+n+1);
	for(int i=1;i<=n;i++){
		int xb=lower_bound(lsh+1,lsh+n+1,p[i].a)-lsh;
		p[i].a=xb+t[xb];t[xb]+=1;//离散化 
	} 
	sort(p+1,p+n+1,cmp);
	for(int i=1;i<=n;i++){
		add(root[i-1],root[i],1,n,p[i].a);
	}
	solve(1,n,1,n);
	for(int i=1;i<=n;i++)
		cout<<ans[i]<<"\n";
	return 0;
}

T4 点餐

依旧不会

posted @ 2025-08-13 14:52  zhangch_qwq  阅读(17)  评论(0)    收藏  举报