NOIP2025模拟9

T1:卡门(kamen)

思路:

模拟。

据说可以用线段树和分块,但是咱还是选择最朴素的叽里呱啦一大坨子的预处理方式。

可以发现 \(c\) 极小,所以我们可以预处理出从第 \(x\) 列丢下去的石头能掉到的位置。

但是这里的部分石头会滚下去怎么办?

我们可以在每次投下石头以后更新一下从该列投下石头的路径。

因为这些路径的上面一些部分是重合的,所以我们可以从上一次的位置往上跳,一直跳到一个空的地方,然后继续模拟题意就好了。

具体实现见代码

代码:

$code$
#include<iostream>
using namespace std;
const int R=3e4+1,C=35;
int r,c,n,x,a[R][C],cnt[C],to[C][R][2];
char ch;
inline void work(int id){
	while(cnt[id]>1&&a[to[id][cnt[id]][0]][to[id][cnt[id]][1]]){
		to[id][cnt[id]][0]=to[id][cnt[id]][1]=0;
		cnt[id]--;
	}//跳到一个空位置 
	int x=to[id][cnt[id]][0],y=to[id][cnt[id]][1];
	while(1){
		bool f=0;
		while(!a[x][y]) x++;//往下跳 
		x--;
		cnt[id]++;
		to[id][cnt[id]][0]=x;
		to[id][cnt[id]][1]=y;//记录下来 
		if(a[x+1][y]==1){//到底了 
			a[x][y]=2;
			break;
		}
		if(y>1&&!a[x+1][y-1]&&!a[x][y-1]){//先左 
			y--;
		}
		else if(y<c&&!a[x+1][y+1]&&!a[x][y+1]){//后右 
			y++;
		}
		else{//再中间 
			f=1;
			a[x][y]=2;
		}
		if(f) break;
	}
} 
int main(){
//	freopen("kamen.in","r",stdin);
//	freopen("kamen.out","w",stdout);
	ios::sync_with_stdio(false);
	cin>>r>>c;
	for(int i=0;i<=r+1;i++){
		for(int j=0;j<=c+1;j++){
			a[i][j]=1;
		}
	}//初始化(给边界框个框框) 
	for(int i=1;i<=r;i++){
		for(int j=1;j<=c;j++){
			cin>>ch;
			a[i][j]=(ch=='X');
		}
	}//输入 
	for(int i=1;i<=c;i++){
		cnt[i]=1;
		to[i][cnt[i]][0]=1;
		to[i][cnt[i]][1]=i;
	}//初始化*2 
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>x;
		work(x);
	}
	for(int i=1;i<=r;i++){
		for(int j=1;j<=c;j++){
			if(a[i][j]==0) cout<<'.';
			if(a[i][j]==1) cout<<'X';
			if(a[i][j]==2) cout<<'O';
		}
		cout<<'\n';
	}//输出 
	return 0;
} 

/*
5 5
3 1 4 0
2 1 3 0
1 3 1 1
3 2 3 1
4 2 0 2

*/

T2:商人(merchant)

思路:

\(topo\) 排序+贪心。

先摆个小结论:一个出度为 \(0\) 的点不会对其他点造成干扰。

对于一个点来讲,把它初始状态设为最大的 \(r\) 一定是可行的(但是不一定最优)。

所以我们可以给所有的边按边权进行一下排序,假设这条边的起点为 \(x\) ,则我们可以使用这条边来更新 \(ans_x\)

若这条边没有别的出边了,那这个点的答案就已经固定了。

此时我们可以删掉这个点,然后可能会有新的没有出边的点产生,然后继续上述操作。

每一轮入队的点,在处理下一条边之前先处理。

取出这个点的每一条进入的边 \(e_i\) ,设其起点为 \(u\),终点为 \(v\),更新 \(u\) 的答案 \(ans_u=min(ans_u,max(r_i,ans_v−p_i))\)

代码:

$code$
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=3e5+5,inf=0x3f3f3f3f;
int n,m,cnt,head[N],ans[N],du[N];
queue<int> q;
bool vis[N];
struct flower{
	int a,b,r,p;
	bool operator < (const flower &css)const{
		return r<css.r;
	}
}a[N];
struct node{
	int to,nxt;
}e[N];
inline void add(int x,int y){
	e[++cnt].to=y;
	e[cnt].nxt=head[x];
	head[x]=cnt;
}
int main(){
//	freopen("merchant.in","r",stdin);
//	freopen("merchant.out","w",stdout);
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>a[i].a>>a[i].b>>a[i].r>>a[i].p;
		du[a[i].a]++;
	}
	sort(a+1,a+1+m);
	memset(ans,0x3f,sizeof(ans));
	for(int i=1;i<=m;i++) add(a[i].b,i);
	for(int i=1;i<=n;i++) if(!du[i]) q.push(i);//topo 
	for(int i=m;i;i--){
		while(!q.empty()){
			int x=q.front();q.pop();
			for(int i=head[x];i;i=e[i].nxt){
				int y=e[i].to;
				if(vis[y]) continue;
				vis[y]=1;
				du[a[y].a]--;
				if(!du[a[y].a]) q.push(a[y].a);
				if(ans[x]!=inf) ans[a[y].a]=min(ans[a[y].a],max(a[y].r,ans[x]-a[y].p));
			}
		}
		if(!vis[i]){
			vis[i]=1;
			du[a[i].a]--;
			if(!du[a[i].a]) q.push(a[i].a);
			ans[a[i].a]=min(ans[a[i].a],a[i].r);
		}
	}
	for(int i=1;i<=n;i++){
		if(ans[i]==inf) cout<<-1<<' ';
		else cout<<ans[i]<<' ';
	}
	return 0;
}

/*
5 5
3 1 4 0
2 1 3 0
1 3 1 1 
3 2 3 1
4 2 0 2

5 7
1 2 0 1
2 1 10 2
2 3 1 3
3 4 5 2
4 2 2 4
3 5 1 5
4 5 0 3

*/
posted @ 2025-11-16 21:59  晏清玖安  阅读(15)  评论(0)    收藏  举报