Loading

BUPT 2024 Spring Training #3(ICPC2023 杭州站)Ag复盘

D - Operator Precedence

求一个长度为 \(2n\) 的序列 \(a_{2n}\) 满足条件 \((a_1 × a_2)+(a_3 × a_4)+\ldots+(a_{2n-1} × a_{2n})=a_1×(a_2+a_3)×\ldots×(a_{2n-2}+a_{2n-1})×a_{2n}\)

solution

构造题显然找特殊规律。

考虑到乘法构造难度大于加法,可以从乘法开始考虑。

注意到不要求 \({a_i}\) 各不相等且 \(a_1×1×1×\ldots ×1×a_{2n}==a_1×a_{2n}\) ,考虑能不能令 \(a_{2n-2}+a_{2n-1}\) 都为 1。

显然任意钦定 \(a_{2n-2}+a_{2n-1}\) 的值之后,只剩未知数 \(a_1\)\(a_{2n}\)

再钦定其一解另一即可。

同理 \(a_1×0×0×\ldots ×0×a_{2n}==0\) ,考虑能不能令 \(a_{2n-2}+a_{2n-1}\) 都为 0。

解法同上。

G - Snake Move

给定 \(n × m\) 地图上的一条长度为 \(k\) 的贪吃蛇。每次操作可以控制贪吃蛇移动一步或者缩短一格蛇身。

对于每个位置,求从初始状态出发最少需要多少次操作使得蛇头到达该处。

Solution

甩个题解吧

每个操作都可以等价看作初始蛇身必然缩短 \(1\),并且同时控制蛇头移动一步或者不移动,因此蛇头到达每个位置的时间越早越好。

最短路建图,相邻格子连代价 \(1\) 的边。

如果一个位置在初始状态下不被蛇身占据,考虑按 Dijkstra 最短路算法第一次访问该点的时刻,蛇头一定不会与蛇身相交。

否则,对于初始状态下第 \(i (2 ≤ i ≤ k)\) 节蛇身所处的位置,显然必须操作 \(k − i\) 次后才能访问该点。因此松弛该点时,需要将最短路长度与
\(k − i\) 取 max。(这一部分没想到)

注:对于取 max 操作的 \(k\) 个点,使用另一个队列升序记录每个状态。那么 Dijkstra 算法的瓶颈——找距离最小的点可以通过比较两个队列的队首
\(\text{O}(1)\) 得到。

void Dij(){
	priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
	q.push(make_pair(0,rt));Dis[rt]=0;memset(Dis,0x3f,sizeof Dis);
	while(!q.empty()){
        int u=q.top().second;q.pop();
        if(vis[u]) continue;vis[u]=1;
        for(int i=head[u];i;i=e[i].nxt){
            int to=e[i].to;
            if(dis[to]){
            	if(Dis[to]>Dis[u]+k-dis[to]+1)
	                Dis[to]=Dis[u]+k-dis[to]+1,
	                q.push(make_pair(Dis[to],to));
			}
            else{	
	            if(Dis[to]>Dis[u]+1)
	                Dis[to]=Dis[u]+1,
	                q.push(make_pair(Dis[to],to));
	        }
        }
    }
}

int main(){
	n=read();m=read();k=read();
	for(int i=1,x,y,tmp;i<=k;i++){
		x=read();y=read();
		tmp=(x-1)*m+y;dis[tmp]=i; 
		if(i==1) rt=tmp;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			char s;cin>>s;
			if(s=='.'){
				for(int t=0;t<4;t++){
					int tx=i+dx[t],ty=j+dy[t];
					if(tx<0||tx>=n||ty<0||ty>=m||s=='#') continue;
					add((i-1)*m+j,(tx-1)*m+ty);
				} 
			}
		}
	}
	Dij();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(Dis[(i-1)*m+j]!=0x3f) ans=(ans+qu(Dis[(i-1)*m+j],2))%Mod;
		}
	}
	return 0;
}

H - Sugar Sweet II

给出 \(n\) 个按随机顺序发生的事件,每个事件可以描述为:若 \(a_i<a_{b_i}\),则 \(a_i\) 增加 \(w_i\)

求每个数的期望。

Solution

先看官方题解:

要求的就是每个事件发生的概率。事件的依赖关系构成一棵基环树。

如果 \(a_i < a_{b_i}\),则事件 \(i\) 必然发生。

\(a_i ≥ a_{b_i} + w_{b_i}\),则事件 \(i\) 必然不发生。

否则,事件 \(i\) 发生当且仅当事件 \(b_i\) 在事件 \(i\) 之前发生。

则对这样子的事件而言,其发生的概率为 \(\frac{1}{L_i !}\),其中 \(L_i\) 为基环树上 \(i\) 到最近的,必定发生的祖先事件的概率。

如果离 \(i\) 最近的是一个必定不发生的事件,则事件 \(i\) 发生的概率为 \(0\)

使用任何 \(\text{O}(n)\) 或者 \(\text{O}(n \text{log} n)\) 的算法处理出 \(L_i\) 即可。

为什么这么算呢,\(L_i!\) 其实就是 \(A_{L_i}^{L_i}\)

即假如 C 必定发生,且 B 依赖 C ,A 依赖 B。如果 A 发生,那么在最终发生的时间排列中一定存在形如 C…B…A 的子序列,所以在算概率时要除以 3 的全排列。

void init(){	
	fact[0]=infact[0]=1;
	for (int i=1; i<=500000; i++ ){
		fact[i]=fact[i-1]*i%mod;
		infact[i]=infact[i-1]*qmi(i,mod-2) % mod;
	}
}

void solve() {
	for(int i=0;i<n;i++) cin>>a[i];
	for(int i=0;i<n;i++) cin>>b[i],b[i]--;
	for(int i=0;i<n;i++) cin>>w[i];
	for (int i=0;i<n;i++){
		if (a[i]<a[b[i]]) ans[i]=a[i]+w[i],f[i]=1;
		else if (a[i]>=a[b[i]]+w[b[i]]) ans[i]=a[i];
		else {g[i]=b[i];rd[b[i]]++;}
	}
	for (int i=0;i<n;i++) {if(!rd[i]) tp.pb(i);}
	for (int i=0; i<tp.size(); i++) {
		int u=tp[i];cir[u]=0;int v=g[u];
		if (v==-1) continue;rd[v]--;
		if (!rd[v]) tp.pb(v);
	}
	for (int i=0;i<n;i++)
		if (cir[i]) ans[i]=a[i];
	for (int i=tp.size()-1;i>=0;i--) {
		int u=tp[i];int v=g[u];
		if (v==-1) dep[u] = 1;
		else if (cir[v]) {
			cir[u]=1;
			ans[u]=a[u];
		} 
		else if (f[v]){
			dep[u]=dep[v] + 1;
			ans[u]=a[u]+w[u]*c(n,dep[u])%mod*fact[n-dep[u]]%mod*infact[n]%mod;
			f[u]=1;
		}
		else ans[u]=a[u];
	}
	for(int i=0;i<ans.size();i++) cout<<x%mod<<" \n";
}

int main() {
	cin>>t;init();
	while(t--){
		cin>>n;
		solve();
	}
	return 0;
}

J - Mysterious Tree

一棵树,可能是链或者菊花,每次询问一条边存在性,确定是链还是菊花。

一共有 \(\lceil{\frac{n}{2}}\rceil +3\) 次询问机会。

Solution

显然对于一条边 \((x,y)\),如果两端点的度数全为 \(1\) 则为链,否则为菊花图。

因此我们只需要找出一个存在的边并询问即可。

再考虑询问策略。

如果我们找到了一条存在的边 \((x,y)\),因为无法统计每个点的度数,因此只能再分别找出与 \(x,y\) 相连的点。

我们随机找一个点 \(p\),若图为菊花图则 \((p,x),(p,y)\) 必定有一个存在,反之可能不存在。若不存在则直接判断。

若存在(我们假设 \((p,x)\) 存在),则可以再随机找一个点 \(q\),若 \((q,x)\) 也存在则必定为菊花图,反之为链图。

因此我们通过 \((x,y)\) 来判断只需不超过 \(3\) 次提问。

那显然剩下的 \(\lceil{\frac{n}{2}}\rceil\) 次提问是为了找出 \((x,y)\)

我们发现,若图为菊花图,那么形如 \((i,i+1)\) 的边必然存在,反之可能不存在。而进行全部询问次数正好与剩余次数相等。

因此不断询问,若存在则按上述步骤解,否则直接判断为链图即可。

M - V-Diagram

给一个 V 图,求一个连续子序列平均值最大的 V 图。

V 图指先严格单调减再严格单调增的序列。

Solution

我们考虑从完整序列的左右分别删除元素。

考虑左侧,若 \(a_1\) 删除后更优,因为 \(a_1>a_2\)\(a_2\) 删除也会更优,因此左侧应删除到 \(a_{i-1}\)

右侧同理。

因此答案为 \([1,i-1],[i+1,n]\) 或者 \([1,n]\)

posted @ 2024-03-22 23:11  KnightL  阅读(104)  评论(8编辑  收藏  举报