首页 > 其他分享 >201117 noi plus 模拟赛

201117 noi plus 模拟赛

时间:2024-11-17 20:46:08浏览次数:1  
标签:ch noi tx ty int cur plus 201117 dis

省流:\(40 + 85 + 48 + 0\)。逆天绿紫黑黑。不能再挂分了,t1 \(100 \to 40\),t2 \(100 \to 85\),t3 \(84 \to 48\)。

T1

给一个 \(n \times m\) 的网格图,每个点只能是 #.ST,若这个点为 # 则这个点是障碍,不能到达,若是 . 则是空地,可以到达,S 是起点,T 是终点。每次你可以走四联通花费 \(1\) 的代价或者到达任意一个曼哈顿距离至多 \(k\) 的点,花费 \(t\) 的代价,求最小代价从起点走到终点。

\(n,m \leq 2000,k \leq 8\)。

由于正解的 \(\Theta(nmk^2)\) 非常的不牛且被赛时的我认为过不了,所以写一下我的赛时爆标做法,虽然赛时写挂了

我们可以给每个点赋予一个势能,势能的大小代表我这个点可以无代价的走几步。那么一个无势能的点可以花费 \(t\) 的代价使它的势能变为 \([1,k]\) 的任意一个(因为至多 \(k\) 不是恰好 \(k\)),还可以不消耗势能花费 \(1\) 的代价走到四联通且是空地的点。一个势能为 \(1\) 的点则可以无代价的走到四联通的是空地的点,消耗 \(1\) 的势能。若势能大于 \(1\),则可以走到四联通的任意一个点,消耗 \(1\) 的势能。发现边权只有 \(0,1,t\) 三种,所以可以用三个队列模拟优先队列,以优化掉 dij 的 \(\log\),时间复杂度 \(\Theta(nmk)\),由于常数较大导致它跑的没有 \(\Theta(nmk^2)\) 快

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2005;
char ch[N][N];
int n,m,k,t,xs,ys,xt,yt,dis[N][N][10],dx[]={0,0,0,1,-1},dy[]={0,1,-1,0,0};
struct node {
	int x,y,z,w;
	bool operator<(const node &o) const {return w<o.w;}
};queue<node> q[3];
bool check() {
	for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) if(ch[i][j]=='#') return false;
	return true;
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n>>m>>k>>t;
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=m; j++) {
			cin>>ch[i][j];
			if(ch[i][j]=='S') xs=i,ys=j;
			if(ch[i][j]=='T') xt=i,yt=j;
		}
	}
	if(check()) {
		int dist=abs(xs-xt)+abs(ys-yt);
		cout<<min({(int)floor(1.0*dist/k)*(t-k)+dist,(int)ceil(1.0*dist/k)*t,dist});
		return 0;
	}
	memset(dis,0x3f,sizeof(dis));
	dis[xs][ys][0]=0;
	q[0].push((node){xs,ys,0,0});
	while(!q[0].empty()||!q[1].empty()||!q[2].empty()) {
		int pos;
		node u=(node){0,0,0,0x3f3f3f3f3f3f3f3f};
		for(int i=0; i<3; i++) {
			if(q[i].empty()) continue;
			if(q[i].front()<u) u=q[i].front(),pos=i;
		}
		q[pos].pop();
		int x=u.x,y=u.y,z=u.z;
		if(z==0) {
			for(int i=1; i<=k; i++) {
				if(dis[x][y][i]>dis[x][y][z]+t) {
					dis[x][y][i]=dis[x][y][z]+t;
					q[2].push((node){x,y,i,dis[x][y][i]});
				}
			}
			for(int i=1; i<=4; i++) {
				int tx=x+dx[i],ty=y+dy[i];
				if(tx<1||tx>n||ty<1||ty>m||ch[tx][ty]=='#') continue;
				if(dis[tx][ty][0]>dis[x][y][0]+1) {
					dis[tx][ty][0]=dis[x][y][0]+1;
					q[1].push((node){tx,ty,0,dis[tx][ty][0]});
				}
			}
		} else if(z==1) {
			for(int i=1; i<=4; i++) {
				int tx=x+dx[i],ty=y+dy[i];
				if(tx<1||tx>n||ty<1||ty>m||ch[tx][ty]=='#') continue;
				if(dis[tx][ty][z-1]>dis[x][y][z]) {
					dis[tx][ty][z-1]=dis[x][y][z];
					q[0].push((node){tx,ty,z-1,dis[tx][ty][z-1]});
				}
			}
		} else {
			for(int i=1; i<=4; i++) {
				int tx=x+dx[i],ty=y+dy[i];
				if(tx<1||tx>n||ty<1||ty>m) continue;
				if(dis[tx][ty][z-1]>dis[x][y][z]) {
					dis[tx][ty][z-1]=dis[x][y][z];
					q[0].push((node){tx,ty,z-1,dis[tx][ty][z-1]});
				}
			}
		}
	}
	int ans=0x3f3f3f3f3f3f3f3f;
	for(int i=0; i<=k; i++) ans=min(ans,dis[xt][yt][i]);
	if(ans<0x3f3f3f3f3f3f3f3f) cout<<ans;
	else cout<<-1;
	return 0;
}

闲话:如果这题只让 \(nmk\) 过应该有个上位蓝到下位紫。

T2

题意:给定一个 \(n\) 个点的树,点有点权,定义一个点 \(u\) 的价值为在树上选择一个点 \(v\),\(u\) 到 \(v\) 的简单路径上的点权异或和。每个点选择 \(v\) 是随机的,求存在一个点的价值 \(\geq t\) 的概率乘以 \(n^n\) 模 \(998244353\) 的结果。

\(n \leq 3 \times 10^5\)。

容易把题意转换为求每个点的价值 \(< t\) 的方案数的乘积,两个点之间的简单路径点权异或和可以被表示为两个点到根的异或再异或上 lca 的点权,这启发我们在 lca 上统计。

假设在 dfs 过程中当前这个点为 \(u\),那么我们就要统计所有经过 \(u\) 且 \(< t\) 的路径 \(s \to t\),将 \(s,t\) 的方案数 \(+ 1\)。异或 \(< t\) 可以用 01 trie 实现,使用 dsu on tree 保留重儿子后,轻儿子暴力加入 01 trie,同时统计有多少个点能使得加入的这个点方案数 \(+ 1\),然后在 01 trie 上打 tag,表示当前插入的这个点对这个 01 trie 上的节点的方案数贡献。最后如果当前 dfs 的是轻儿子,暴力将 01 trie 上的 tag 加回到每个点,然后删除。

时间复杂度 \(\Theta(n \log n \log V)\),常数较大,需要卡常。

代码:

#include<bits/stdc++.h>
#pragma GCC optimize("Ofast,unroll-loops")
using namespace std;
const int N=3e5+5,p=998244353;
long long t,w[N],dis[N];
vector<int> ve,id[N<<5];
int n,Sz[N],son[N],tot=0,ch[N<<5][2],sz[N<<5],tag[N<<5],cnt[N],head[N],ecnt=0;
struct edge {int to,nxt;}e[N<<1];
inline void addedge(int u,int v) {e[++ecnt]=(edge){v,head[u]};head[u]=ecnt;return;} 
void dfs1(int u,int pre) {
	int mx=0;
	Sz[u]=1,dis[u]=dis[pre]^w[u];
	for(int i=head[u]; i; i=e[i].nxt) {
		int v=e[i].to;
		if(v==pre) continue;
		dfs1(v,u);
		Sz[u]+=Sz[v];
		if(Sz[v]>mx) {
			mx=Sz[v];
			son[u]=v;
		}
	}
	return;
}
inline void add(int ii,long long x) {
	int cur=0;
	for(int i=31; i>=0; --i) {
		bool b=(x>>i)&1;
		if(!ch[cur][b]) ch[cur][b]=++tot;
		cur=ch[cur][b];
		sz[cur]++;
		cnt[ii]-=tag[cur];
	}
	id[cur].emplace_back(ii);
	return;
}
inline int query(long long x) {
	int cur=0,ans=0;
	for(int i=31; i>=0; --i) {
		bool b1=(x>>i)&1,b2=(t>>i)&1;
		if(b2) {
			if(ch[cur][b1^1]) tag[ch[cur][b1]]++,ans+=sz[ch[cur][b1]],cur=ch[cur][b1^1];
			else {
				tag[ch[cur][b1]]++,ans+=sz[ch[cur][b1]];
				break;
			}
		} else if(ch[cur][b1]) cur=ch[cur][b1];
		else break;
	}
	return ans;
}
void collect(int u,int pre) {
	ve.emplace_back(u);
	for(int i=head[u]; i; i=e[i].nxt) {
		int v=e[i].to;
		if(v==pre) continue;
		collect(v,u);
	}
	return;
}
void dfstrie(int u,int sum) {
	if(u) sum+=tag[u];
	for(int i=0; i<id[u].size(); ++i) cnt[id[u][i]]+=sum;
	if(ch[u][0]) dfstrie(ch[u][0],sum);
	if(ch[u][1]) dfstrie(ch[u][1],sum);
	return;
}
void dfs2(int u,int pre,bool hv) {
	for(int i=head[u]; i; i=e[i].nxt) {
		int v=e[i].to;
		if(v==pre||v==son[u]) continue;
		dfs2(v,u,0);
	}
	if(son[u]) dfs2(son[u],u,1);
	for(int i=head[u]; i; i=e[i].nxt) {
		int v=e[i].to;
		if(v==pre||v==son[u]) continue;
		ve.clear();collect(v,u);
		for(int j=0; j<ve.size(); j++) cnt[ve[j]]+=query(dis[ve[j]]^w[u]);
		for(int j=0; j<ve.size(); j++) add(ve[j],dis[ve[j]]);
	}
	cnt[u]+=query(dis[u]^w[u]);
	add(u,dis[u]);
	if(!hv) {
		dfstrie(0,0);
		for(int i=0; i<=tot; i++) sz[i]=tag[i]=ch[i][0]=ch[i][1]=0,id[i].clear();
		tot=0;
	}
	return;
}
inline int qpow(int a,int b) {
	int ans=1;
	while(b) {
		if(b&1) ans=1ll*ans*a%p;
		a=1ll*a*a%p;
		b>>=1;
	}
	return ans;
}
inline long long read() {
	int f=1;
    long long x=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
signed main() {
	n=read();
	for(int i=1; i<n; ++i) {
		int u,v;
		u=read(),v=read();
		addedge(u,v),addedge(v,u);
	}
	for(int i=1; i<=n; ++i) w[i]=read();
	t=read();
	dfs1(1,0);dfs2(1,0,0);
	int ans=1;
	for(int i=1; i<=n; ++i) ans=1ll*ans*(cnt[i]+(w[i]<t))%p;
	cout<<(qpow(n,n)-ans+p)%p;
	return 0;
}

T3

原题:AT_arc063_f。

还不会。

T4

AT_arc070_f 加强版。

还不会。

标签:ch,noi,tx,ty,int,cur,plus,201117,dis
From: https://www.cnblogs.com/System-Error/p/18551087

相关文章

  • NOIP2024加赛5
    暴力操作(opt)拜谢丁真首先题目有一个很明显的性质:我们肯定只会对前\(\cfrac{n+1}{2}\)个数进行操作使它变小。最后的答案很明显没看出来具有二分答案的性质,考虑怎么check。实则就是要判断前\(\cfrac{n+1}{2}\)个数是否都能\(\lemid\)。我们可以方便的找出\(a_i\)变......
  • NOIP2016 提高组 愤怒的小鸟
    NOIP2016提高组愤怒的小鸟比较板的状压dp,结果做了3天才写完。算法一暴力搜索所有猪的分组情况,同组要满足能一根抛物线打完。时间复杂度\(O(n^n\timesn)\),实现的好的话大概能过\(60pts\)。最难写的大概是函数判断的部分。想一次写对就一定要打好草稿先理清思路。这是经验......
  • NOIP2021 做题笔记
    这次又被抓过去写noip2021了\(qaq\)P7960[NOIP2021]报数可以用类似于质数筛的方法筛一遍,做到\(\mathcalO(\)值域\()\)的预处理,以及\(\mathcalO(1)\)的查询。#include<bits/stdc++.h>usingnamespacestd;#definelllonglong#definemxn10000010#definemxm200......
  • CSP/信奥赛C++语法基础刷题训练(12):洛谷P1047:[NOIP2005 普及组] 校门外的树
    CSP/信奥赛C++语法基础刷题训练(12):洛谷P1047:[NOIP2005普及组]校门外的树题目描述某校大门外长度为lll的马路上有一排树,每两棵相邻的树之间的间隔都是......
  • Element Plus
    快速入门:然后我在src下创建了一个Button.vue文件,再去Element-plus官网查找组件的源码常用组件表格:<scriptlang="ts"setup>import{Delete,Edit,}from'@element-plus/icons-vue'consttableData=[{title:'标题1',category:&#......
  • springboot3整合mybatisplus问题Invalid value type for attribute 'factoryBeanObjec
    版本说明:JDK版本:17springboot版本:3.3.5问题分析:springboot版本与mybatisplus版本不兼容解决办法:将mybatisplus版本替换为以下版本<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>......
  • [考试记录] 2024.11.16 noip模拟赛14
    T1字符串构造机考虑将一个LCP条件拆分成两个,一个是相等的部分,使用并查集维护,另一个是不等的部分,两个串末尾的字符一定不相等,随便那啥维护。对于非法情况就是在同一个相等联通块内有不相等的条件。然后考虑从前往后贪心即可。#include<bits/stdc++.h>usingnamespacestd;#d......
  • CSP&NOIP 2024游记
    前言还没想好写什么,先留着。八月原计划是高中不搞OI了,专心搞文化课。初三一年,完全对自己失去信心了,颓了一年,什么都没有学会,实力不进反退,真的就只配当J组选手吧。但是迫于家长的压力,还是报了。也没有复习,此时以前的同学已经开始集训了。之后就是军训,高中正式开始了。九月开学......
  • 241116 noip 模拟赛
    省流:\(100+100+100+5\)。T1题意:给一个括号序列\(s\),求出长度最小的\(s\)的子序列\(t\),满足\(t\)是合法括号序列且删掉\(t\)后\(s\)是一个特殊的序列。定义特殊的序列为长度\(2n\),前\(n\)个都是(,后\(n\)个都是)。\(n\leq3\times10^6\)。可以枚举特......
  • NOIP集训 P4137 Rmq Problem / mex 题解
    前置指使:可持久化线段树题解:P4137RmqProblem/mex有一个长度为\(n\)的数组\(\{a_1,a_2,...,a_n\}\)。\(m\)次询问,每次询问一个区间内最小没有出现过的自然数。Input第一行,两个正整数\(n,m\)。第二行,\(n\)个非负整数\(a_1,a_2,...,a_n\)。接下来\(m\)行,每......