Codeforces Round 927 (Div. 3)(A,B,C,D,E,F,G)

news2024/12/23 9:52:02

这场简单些,E题是个推结论的数学题,沾点高精的思想。F是个需要些预处理的DP,G题是用exgcd算边权的堆优化dijkstra。C题有点骗,硬啃很难做。


A Thorns and Coins

题意:

在你的电脑宇宙之旅中,你偶然发现了一个非常有趣的世界。这是一条有 n n n 个连续单元格的路径,每个单元格可能是空的,也可能包含荆棘或一枚硬币。在一次移动中,你可以沿着这条路径移动一个或两个单元格,前提是目的地单元格不包含荆棘(并且属于这条路径)。如果您移动到有硬币的格子,您就会拾起它。

这里,绿色箭头代表合法移动,红色箭头代表非法移动。

您想要收集尽可能多的硬币。如果你从路径最左边的单元格开始,请找出你在已发现世界中最多可以收集到的硬币数量。

思路:

模拟以下过程即可。一步一步走,如果是金币就捡,如果是地刺就尝试跳一步,下一步还是地刺就结束游戏。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int T,n;
string s;

int main(){
	cin>>T;
	while(T--){
		cin>>n>>s;
		int cnt=0;
		for(int i=0;i<=n;i++){
			if(s[i]=='@')cnt++;
			if(s[i]=='.')continue;
			if(s[i]=='*'){
				if(s[i+1]!='*')continue;
				else break;
			}
		}
		cout<<cnt<<endl;
	}
	return 0;
}

B Chaya Calendar

题意:

查亚部落相信世界末日有 n n n 个征兆。随着时间的推移,人们发现第 i i i 个征兆每隔 a i a_i ai 年( a i a_i ai 年、 2 ⋅ a i 2 \cdot a_i 2ai 年、 3 ⋅ a i 3 \cdot a_i 3ai 年、 … \dots 年)就会出现。

根据传说,世界末日必须按顺序出现。也就是说,首先要等待第一个征兆出现,然后严格按照这个顺序,第二个征兆才会出现,以此类推。也就是说,如果第 i i i 个征兆在 x x x 年出现,那么部落就会从 x + 1 x+1 x+1 年开始等待第 ( i + 1 ) (i+1) (i+1) 个征兆的出现。

哪一年会出现第 n n n 个征兆,即世界末日会在哪一年发生?

思路:

这个题的数据居然没卡 O ( 1 0 6 ∗ n ) O(10^6*n) O(106n)的做法,导致赛后一大批萌新被叉。

一个比较明显的思路就是模拟一下每个征兆出现的年数,假设算出了前 i − 1 i-1 i1 个的征兆最后一个征兆发生的年份是 n w nw nw,那么第 i i i 年发生征兆的年份是大于 n w nw nw 的最小倍数。推一下式子递推即可。

code:

#include <iostream>
#include <cstdio>
using namespace std;

int T,n,nw;

int main(){
	cin>>T;
	while(T--){
		cin>>n;
		nw=0;
		for(int i=1,t;i<=n;i++){
			cin>>t;
			nw=(nw/t+1)*t;
		}
		cout<<nw<<endl;
	}
	return 0;
}

C LR-remainders

题意:

给你一个长度为 n n n 的数组 a a a 、一个正整数 m m m 和一串长度为 n n n 的命令。每条命令要么是字符 “L”,要么是字符 “R”。

按照字符串 s s s 中的顺序处理所有 n n n 命令。处理一条命令的步骤如下:

  • 首先,输出数组 a a a 中所有元素的乘积除以 m m m 后的余数。
  • 然后,如果命令是 “L”,则从数组 a a a 中删除最左边的元素;如果命令是 “R”,则从数组 a a a 中删除最右边的元素。

注意,每次移动后,数组 a a a 的长度都会减少 1 1 1 ,处理完所有命令后,数组 a a a 将为空。

请编写一个程序,按照字符串 s s s 中的顺序(从左到右)处理所有命令。

思路:

一般思路是模拟操作的思路,然后算出 现在区间的数的乘积的余数,但是这东西不好算。要么你写高精算前缀积,但是这样要实现高精乘法和高精除高精。要么算出整段区间的乘积对模数的余数,然后用逆元来乘实现模意义下的除法,不过这个思路是错的。因为模数 m m m 不能保证和所有 a i a_i ai 互质,欧拉定理用不了,费马小定理更用不了。逆元算不出来。

所以考虑其他思路,发现虽然乘逆元缩减区间实现不了,但是区间操作的过程我们可以反过来,把乘逆元缩减区间变成乘这个数扩展区间。先沿着缩减区间的步骤走到终点,再从终点一步一步走回来,这和递归的思路很像。

考虑递归,先沿着操作递归到终点。然后返回的时候返回区间乘积的余数,顺便记录每个位置的余数,之后顺序输出即可。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn=2e5+5;
typedef long long ll;

int T,n,m,a[maxn];
string op;

vector<int> ans;
ll print(int x,int l,int r){
	if(x>=n)return 1;
	ll tmp;
	if(op[x]=='L')tmp=a[l]*print(x+1,l+1,r)%m;
	else tmp=a[r]*print(x+1,l,r-1)%m;
//	printf("%d ",tmp);
	ans.push_back(tmp);
	return tmp;
}

int main(){
	cin>>T;
	while(T--){
		cin>>n>>m;
		for(int i=1;i<=n;i++)
			cin>>a[i];
		cin>>op;
		ans.clear();
		print(0,1,n);
		for(auto it=ans.rbegin();it!=ans.rend();it++)
			cout<<*it<<" ";
		puts("");
	}
	return 0;
}

D Card Game

题意:

两名玩家正在玩一款在线纸牌游戏。游戏使用一副 32 张牌。每张牌都有花色和等级。共有四种花色:梅花、方块、红心和黑桃。我们将分别用字符 “C”、“D”、"H "和 "S "对它们进行编码。共有 8 个等级,依次递增:‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’.

每张牌都用两个字母表示:等级和花色。例如,红心 8 表示为 8H。

游戏开始时,选择一种花色作为王牌花色

在每一轮游戏中,玩家都要这样出牌:第一位玩家将自己的一张牌放在桌上,第二位玩家必须用自己的一张牌击败这张牌。之后,两张牌都被移至弃牌堆。

如果两张牌的花色相同,且第一张牌的等级高于第二张牌,那么这张牌就能打败另一张牌。例如,8S 可以打败 4S。此外,一张王牌可以无视等级打败任何一张非王牌,比如,如果王牌花色是梅花(“C”),那么 3C 可以击败 9D。请注意,王牌只能被等级更高的王牌击败。

游戏中一共进行了 n n n 轮,因此弃牌堆中现在有 2 2 2$ 张牌。你想重建游戏中的回合,但是弃牌堆中的牌是洗过的。请找出游戏中可能出现的 n n n 个回合。

思路:

要注意到两个东西:

  1. 王牌花色可以无视点数打败其他花色的牌
  2. 每种牌只有一张,每张牌互不相同

所以一个很明显的思路就是先顺序输出其他花色,两个两个输出,其他花色剩一张就用王牌花色凑一张,最后输出王牌花色。所以无解的判定条件很明显,就是其他花色中 奇数张的花色 的个数不超过王牌花色牌个数即可。因为题目给的是偶数张牌,所以不需要是否是奇数张牌。

考虑如何输出,不难想到用set存储每张牌,开4个set存储四种花色。不过输出的时候判断每种花色是不是王牌花色比较麻烦。可以输入的时候直接把王牌花色的牌放到单独的set中,不放到4个set对应的花色中,其他花色的牌正常放即可。

code:

#include <iostream>
#include <cstdio>
#include <set>
#include <cstring>
using namespace std;

int T,n;
char wp;

void pcard(int x,int color=0){
	printf("%d%c ",x,((color)?" CDHS"[color]:wp));
}

int main(){
	cin>>T;
	while(T--){
		cin>>n>>wp;
		n<<=1;
		set<int> s[5],t; 
		for(int i=1;i<=n;i++){
			string tmp;
			cin>>tmp;
			if(tmp[1]==wp)t.insert(tmp[0]-'0');
			else {
				switch(tmp[1]){
					case 'C':s[1].insert(tmp[0]-'0');break;
					case 'D':s[2].insert(tmp[0]-'0');break;
					case 'H':s[3].insert(tmp[0]-'0');break;
					case 'S':s[4].insert(tmp[0]-'0');break;
				}
			}
		}
		
		if((s[1].size()&1)+(s[2].size()&1)+(s[3].size()&1)+(s[4].size()&1)<=t.size()){
			for(int i=1;i<=4;i++){
				while(!s[i].empty()){
					pcard(*s[i].begin(),i);
					s[i].erase(s[i].begin());
					
					if(s[i].empty()){
						pcard(*t.begin());
						t.erase(t.begin());
					}
					else {
						pcard(*s[i].begin(),i);
						s[i].erase(s[i].begin());
					}
					printf("\n");
				}
			}
			while(!t.empty()){
				pcard(*t.begin());
				t.erase(t.begin());
				pcard(*t.begin());
				t.erase(t.begin());
				printf("\n");
			}
		}
		else printf("IMPOSSIBLE\n");
	}
	return 0;
}

E Final Countdown

题意:

你身处一个即将爆炸并摧毁地球的核实验室。您必须在最后倒计时为零之前拯救地球。

倒计时由 n n n ( 1 ≤ n ≤ 4 ⋅ 1 0 5 1 \le n \le 4 \cdot 10^5 1n4105 ) 个机械指示器组成,每个指示器显示一位小数。你注意到,当倒计时的状态从 x x x 变为 x − 1 x-1 x1 时,并不是一蹴而就的。相反,每个数字的变化都需要一秒钟。

因此,举例来说,如果倒计时显示 42,那么它将在一秒钟内变为 41,因为只有一位数发生了变化;但如果倒计时显示 2300,那么它将在三秒钟内变为 2299,因为最后三位数发生了变化。

找出倒计时归零前还剩多少时间。

思路:

考虑到只要有一位退位就会用掉一秒(假设把个位上的数减一也看作退一位),而减一的逆过程就是加一,被减数减 1 1 1 退位的次数和减数加 1 1 1 产生的进位的次数是相同的,因此我们把一个数不断减一到零产生的退位次数相当于给零加一不断加到这个数产生的进位次数。

而不断加 1 1 1,每个数位上会产生多少进位,也就是变化呢。以12345举例,不难发现个位会变化12345次,十位会变化1234次,百位会变化123次,千位变化12次,各位变化1次,总的变化次数就是 12345 + 1234 + 123 + 12 + 1 = 13715 12345+1234+123+12+1=13715 12345+1234+123+12+1=13715 次。

不过直接写高精实现高精加法的话,由于 n = 4 ∗ 1 0 5 n=4*10^5 n=4105,一个高精数是 n n n 位, n n n 个高精数相加的复杂度是 n 2 n^2 n2 的。会TLE。

把式子写成竖式的形式,就会发现一个规律:

12345
 1234
  123
   12
    1
-----
13715

居然!由于是对称的,个位上的数相当于前五个 数位上每个数的和 模10(多出来的数进位了),十位上的数相当于前四位上每个数的和加上来自个位的进位 模10,同理百千万位上的数。

这提示我们可以用前缀和算出每个数位上的数,最后处理一下进位即可,前缀和 和 处理进位的时间复杂度是 O ( n ) O(n) O(n) 的,而前缀和不会超 9 ∗ 4 ∗ 1 0 5 9*4*10^5 94105,不会爆int。

code:

幽默高精度(没有用到就不用看了,放在这里纯纯纪念意义)

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

int T,n;

struct bigint{
	vector<int> val;
	
	bigint(int x=0){
		do{
			val.push_back(x%10);
			x/=10;
		}while(x);
	}
	bigint(string s){
		for(auto it=s.rbegin();it!=s.rend();it++)
			val.push_back(*it-'0');
		while(val.size()>1 && val.back()==0)
			val.pop_back();
	}
	bigint(vector<int> a){
		val=a;
	}
	void print(){
		for(auto it=val.rbegin();it!=val.rend();it++)cout<<*it;
		puts("");
	}
	bool eq0(){
		return val.size()==1 && val[0]==0;
	}
	
	friend bigint operator+(bigint a,bigint b);
	friend bigint operator>>(bigint a,int x);
};

bigint operator+(bigint a,bigint b){
	vector<int> c;
	int n=max(a.val.size(),b.val.size());
	for(int i=0;i<n;i++)
		c.push_back(((a.val.size()>i)?a.val[i]:0)+((b.val.size()>i)?b.val[i]:0));
	int ct=0;
	for(int i=0;i<c.size();i++){
		c[i]+=ct;
		ct=c[i]/10;
		c[i]%=10;
	}
	while(ct){
		c.push_back(ct%10);
		ct/=10;
	}
	return bigint(c);
}
bigint operator>>(bigint a,int x){
	if(a.val.size()<=x)return bigint(0);
	else {
		vector<int> b;
		for(int i=x;i<a.val.size();i++)
			b.push_back(a.val[i]);
		return bigint(b);
	}
	return a;
}

int main(){
	cin>>T;
	while(T--){
		cin>>n;
		string tmp;
		cin>>tmp;
		vector<int> s(n);
		for(int i=0;i<n;i++){
			s[i]=((i>0)?s[i-1]:0)+tmp[i]-'0';
		}
		reverse(s.begin(),s.end());
		int ct=0;
		for(int i=0;i<s.size();i++){
			s[i]+=ct;
			ct=s[i]/10;
			s[i]%=10;
		}
		while(ct){
			s.push_back(ct%10);
			ct/=10;
		}
		while(s.size()>1 && s.back()==0)s.pop_back();//去除前导零
		
		for(auto it=s.rbegin();it!=s.rend();it++)cout<<*it;
		puts("");
	}
	return 0;
}

F Feed Cats

题意:

在这个有趣的游戏中,您需要喂养来来往往的猫咪。游戏的关卡由 n n n 步组成。有 m m m 只猫; i i i 只猫出现在 l i l_i li r i r_i ri (包括 r i r_i ri )。在每一步中,您可以喂养当前出现的所有猫咪,或者什么也不做。

如果您喂同一只猫超过一次,它就会暴饮暴食,您就会立即输掉游戏。您的目标是在不导致任何一只猫暴食的情况下喂食尽可能多的猫。

找出您能喂养的最大猫咪数量。

从形式上看,您需要从 1 1 1 n n n 的线段中选择几个整数点,使得在给定的线段中,没有一个线段覆盖两个或两个以上所选的点,并且有尽可能多的线段覆盖到点。

思路:

如果我们从左到右走,要喂一个点上的猫,那么一定不能和前面的冲突,否则就会喂死,所以我们枚举包含这个这个点的所有猫 薛定谔的出现 区间,找到最小的左区间,在次之前喂猫就没有问题了。

假设我们现在尝试喂点 i i i 处的猫,最小左端点是 l l l,如果 l l l 之前有一种喂法能使得喂到的猫最多,那么这个喂法加上点 i i i 处的猫的个数就是 喂点 i i i 处的猫,使得喂到的猫最多的喂法。DP的思路就比较显然了。

d p [ i ] dp[i] dp[i] 表示喂点 i i i 处的猫,使得喂到的猫最多的喂法,还需要维护前缀最大值 p m x [ i ] pmx[i] pmx[i] 表示前 i i i 个位置的最大 d p dp dp 值,点 i i i 处的猫的个数是 n u m [ i ] num[i] num[i]。转移方程就是 d p [ i ] = p m x [ i − l ] + n u m [ i ] dp[i]=pmx[i-l]+num[i] dp[i]=pmx[il]+num[i]

发现暴力找 l l l 太慢了,考虑优化。最直观的想法就是模拟一下从前往后走的过程,用set维护一下当前位置的猫。具体来说使用两个set<pair<int,int>>,第一个set第一维存储猫的左端点,第二维存储右端点,第二个set反过来,第一维存储右端点,第二维存储左端点。

每次向右移动一位,查询第二个set,把右端点小于当前位置的猫都删掉,同步删掉第一个set中的猫。然后将所有左端点正好是这个位置的猫加入两个set进来,这里可以预先对猫区间按左端点排序,这样就不用遍历猫区间来加入猫了,用个指针边加边移动即可。之后最小左端点看第一个set,猫的个数直接查询set的大小即可。

代码片段如下:
因为猫区间是可以重复的,所以需要多加一维存储没什么用的信息,来区分每个元素。

sort(cat+1,cat+m+1);//猫区间
set<pair<pair<int,int>,int> > s1,s2;
for(int pos=1,i=1;pos<=n;pos++){
	while(!s2.empty() && s2.begin()->first.first<pos){
		pair<pair<int,int>,int> x=*s2.begin();
		s1.erase(make_pair(make_pair(x.first.second,x.first.first),x.second));
		s2.erase(x);
	}
	while(i<=m && cat[i].first<=pos){
		s1.insert(make_pair(cat[i],i));
		s2.insert(make_pair(make_pair(cat[i].second,cat[i].first),i));
		i++; 
	}
	pre[pos]=(s1.size())?s1.begin()->first.first:pos;//最小左区间
	num[pos]=s1.size();//猫个数
}

实际上大佬的写法更为简洁(没完全看懂):
在这里插入图片描述

模拟一下大佬的, n u m num num 数组使用差分思想来实现,然后用指针 p p p 来表示位置。

sort(cat+1,cat+m+1);
for(int i=1;i<=n;i++)num[i]=0;
for(int i=1,p=1,l,r;i<=m;i++){
	l=cat[i].first;
	r=cat[i].second;
	num[l]++;
	num[r+1]--;
	for(;p<l;p++)pre[p]=p;
	for(;p<=r;p++)pre[p]=l;
}

还有一种更巧妙的 O ( n ) O(n) O(n) 的写法:指路

在这里插入图片描述

这里相当于直接桶排了。

code:

#include <iostream>
#include <cstdio>
#include <set>
#include <algorithm>
using namespace std;
const int maxn=1e6+5;
const int maxm=2e5+5;
typedef long long ll;

int T,n,m;
pair<int,int> cat[maxm];
int pre[maxn],num[maxn];//i点所在猫占领区间左端点 i点猫个数  
int dp[maxn],pmx[maxn];

int main(){
	cin>>T;
	while(T--){
		cin>>n>>m;
		for(int i=1;i<=m;i++)
			cin>>cat[i].first>>cat[i].second;
		sort(cat+1,cat+m+1);
		
		for(int i=1;i<=n;i++)
			num[i]=0;
		for(int i=1,p=1,l,r;i<=m;i++){
			l=cat[i].first;
			r=cat[i].second;
			num[l]++;
			num[r+1]--;
			for(;p<l;p++)pre[p]=p;
			for(;p<=r;p++)pre[p]=l;
		}
			
		
		for(int i=1;i<=n;i++){
			num[i]+=num[i-1];
			dp[i]=pmx[pre[i]-1]+num[i];
			pmx[i]=max(pmx[i-1],dp[i]);
		}
		cout<<pmx[n]<<endl;
	}
	return 0;
}

G Moving Platforms

题意:

有一个游戏,你需要穿过一个迷宫。迷宫由 n n n 个平台组成,由 m m m 条通道连接。

每个平台都处于某个级别 l i l_i li ,是一个从 0 0 0 H − 1 H - 1 H1 的整数。在一个步骤中,如果你目前在平台 i i i 上,你可以留在上面,或者移动到另一个平台 j j j 上。要移动到平台 j j j ,它们必须通过通道相连,而且它们的级别必须相同,即 l i = l j l_i = l_j li=lj

每走一步,所有平台的级别都会发生变化。对于所有的 i i i ,平台 i i i 的新水平面计算为 l i ′ = ( l i + s i )   m o d   H l'_i = (l_i + s_i) \bmod H li=(li+si)modH

你从平台 1 1 1 开始。求到达平台 n n n 所需的最少步数。

思路:

只有两个点 u , v u,v u,v 的级别相同的时候才能走它们相连的边,所以可以列出式子,假如在时间 x x x 时两个点级别相同,则有: l u + ( x − 1 ) ∗ s u ≡ l v + ( x − 1 ) ∗ s v ( m o d H ) l_u+(x-1)*s_u\equiv l_v+(x-1)*s_v\pmod H lu+(x1)sulv+(x1)sv(modH) x ∗ ( s u − s v ) ≡ l v − l u + s u − s v ( m o d H ) x*(s_u-s_v)\equiv l_v-l_u+s_u-s_v\pmod H x(susv)lvlu+susv(modH)
如果我们令 a = s u − s v , c = l v − l u + s u − s v a=s_u-s_v,c=l_v-l_u+s_u-s_v a=susv,c=lvlu+susv,那么式子就转化为了 a ∗ x ≡ c ( m o d H ) a*x\equiv c\pmod H axc(modH)
这是一个一次同余式子,使用exgcd(拓展欧几里得定理)来求解。

求解得到 d = g c d ( a , H ) d=gcd(a,H) d=gcd(a,H) x ′ x' x,令 x 0 = c / d ∗ x ′ x_0=c/d*x' x0=c/dx ,则 x 0 x_0 x0 a ∗ x ≡ c ( m o d H ) a*x\equiv c\pmod H axc(modH) 的一个特解,令 t = H / d t=H/d t=H/d,则 x = x 0 + k ∗ t ( k 为整数 ) x=x_0+k*t\quad(k为整数) x=x0+kt(k为整数) 为上式的通解。

假设现在时间已经过去了 t m tm tm,我们要找最近的一次两个水平面相同,就是要求得 x = x 0 + k ∗ t > t m x=x_0+k*t\gt tm x=x0+kt>tm k > t m − x 0 t k\gt \frac{tm-x_0}{t} k>ttmx0 ∵ k 为整数 \because k为整数 k为整数 ∴ k = ⌊ t m − x 0 t ⌋ + 1 \therefore k=\left\lfloor\frac{tm-x_0}{t}\right\rfloor+1 k=ttmx0+1 不过要实现下取整的时候不能直接使用C++的整数除法,因为这个是向 0 0 0 取整的,所以在 t m < x 0 tm\lt x_0 tm<x0 时反而相当于是上取整。而且我们不能保证 t m ≥ x 0 tm\ge x_0 tmx0

实际上 x = x 0 + k ∗ t x=x_0+k*t x=x0+kt 我们可以看作是模 t t t 同余 x 0 x_0 x0 的一系列数,所以我们可以对 x 0 x_0 x0 取模,得到的数仍然是通解, t t t 是正的, t m tm tm 也是正的,所以 x = x 0 % t − t < t m x=x_0\%t-t\lt tm x=x0%tt<tm,用这个 x x x 就没问题了。

这样就算出来了下一次两个点级别相同是什么时候,这东西就相当于一个边权,我们直接跑最短路即可。

因为是个边权一样的东西,所以可以对每个边预处理exgcd的特解与通解的变化量,然后要用某个边的时候就再用当前的时间来算。

code:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const ll inf=1e18;

ll T,n,m,mod;
ll l[maxn],s[maxn];

int head[maxn],cnt;
struct edge{
	int v,nxt;
}e[maxn<<1];
void add(int u,int v){
	e[++cnt].v=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}

ll exgcd(ll a,ll b,ll &x,ll &y){
	if(!b){
		x=1;y=0;
		return a;
	}
	ll d=exgcd(b,a%b,x,y);
	ll z=x;
	x=y;
	y=z-y*(a/b);
	return d;
}
ll f(int u,int v,ll tm){
	ll a=((s[u]-s[v])%mod+mod)%mod,b=mod,c=((l[v]-l[u]+s[u]-s[v])%mod+mod)%mod;
	ll x,y;
	ll d=exgcd(a,b,x,y);
	if(c%d)return -1;
	x=c/d*x;
	ll t=b/d;
	x=x%t-t;
	ll k=(tm-x)/t+1;
	return x+k*t;
}

ll f2(int u,int v,ll tm){//暴力做法,用于对拍
	set<ll> S;
	for(ll t=tm+1,ans;;t++){
		ans=(((t-1)*(s[u]-s[v])+(l[u]-l[v]))%mod+mod)%mod;
		if(ans==0)return t;
		if(S.count(ans))return -1;
		else S.insert(ans);
	}
}

int main(){
	cin>>T;
	while(T--){
		cin>>n>>m>>mod;
		for(int i=1;i<=n;i++)
			cin>>l[i];
		for(int i=1;i<=n;i++)
			cin>>s[i];
		for(int i=1;i<=n;i++)head[i]=0;
		cnt=0;
		for(int i=1,u,v;i<=m;i++){
			cin>>u>>v;
			add(u,v);
			add(v,u);
		}
		
		vector<ll> d(n+1,inf);
		vector<bool> vis(n+1,false);
		d[1]=0;
		priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > h;
		h.push(make_pair(d[1],1));
		while(!h.empty()){
			int u=h.top().second;
			if(u==n)break;
			h.pop();
			if(!vis[u])vis[u]=true;
			else continue;
			for(int i=head[u],v;i;i=e[i].nxt){
				v=e[i].v;
				ll tm=f(u,v,d[u]);
				if(~tm && tm<d[v]){
					d[v]=tm;
					h.push(make_pair(d[v],v));
				}
			}
		}
		
		if(d[n]!=inf)cout<<d[n]<<endl;
		else cout<<-1<<endl;
	}
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1460766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode 0105.从前序与中序遍历序列构造二叉树:分治(递归)——五彩斑斓的题解(若不是彩色的可以点击原文链接查看)

【LetMeFly】105.从前序与中序遍历序列构造二叉树&#xff1a;分治&#xff08;递归&#xff09;——五彩斑斓的题解&#xff08;若不是彩色的可以点击原文链接查看&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/construct-binary-tree-from-preorder-a…

java数据类型、运算符

一、数据的表示详解 1.1 整数在计算机中的存储原理 任何数据在计算机中都是以二进制表示的。那这里肯定有人问&#xff0c;什么是二进制啊&#xff1f;所谓二进制其实就是一种数据的表示形式&#xff0c;它的特点是逢2进1。 数据的表示形式除了二进制&#xff08;逢2进1&…

Https证书续签-acme.sh-腾讯云之DnsPod

ename 域名切换到 DnsPod 上面解析 可以先看下之前的 acme.sh 介绍文章然后再来次补充更多。 之前说过了 acme.sh 在阿里云下的使用。 这里做个后续补充 之前的域名是在 ename 上的 &#xff0c;为了自动续签切换到 DnsPod 上面解析 注意事项 可以把原来 ename 上的解析先导出…

Android全新UI框架之Jetpack Compose入门基础

Jetpack Compose是什么 如果有跨端开发经验的同学&#xff0c;理解和学习compose可能没有那么大的压力。简单地说&#xff0c;compose可以让Android的原生开发也可以使用类似rn的jsx的语法来开发UI界面。以往&#xff0c;我们开发Android原生页面的时候&#xff0c;通常是在xml…

【八股文面试】Java基础常见面试题总结(上)

Java基础常见面试题总结(上) Java有哪些特性 简单易学&#xff1b;面向对象&#xff08;封装&#xff0c;继承&#xff0c;多态&#xff09;&#xff1b;平台无关性&#xff08; Java 虚拟机实现平台无关性&#xff09;&#xff1b;支持多线程&#xff08; C 语言没有内置的多…

Springcloud:LiteFlow

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 一、LiteFlow简介 二、规则编排关键字及语法 1、THEN&#xff1a; 2、WHEN&#xff1a; 3、AND&#xff1a; 4、OR&#xff1a; 5、IF&#xff1a; 6、ELSE&…

手动代码实现神经网络

网络结构 第一层有13个神经元&#xff0c;第二层8个神经元&#xff0c;第三层是输出层&#xff1b;其中第一层的激活函数是relu&#xff0c;第二层是sigmoid 代码实现 # 导入库 import torch import torch.nn as nn from torch.nn import functional as F # 确定数据 torch…

使用IntelliJ IDEA查看接口的全部实现方法

在大型Java项目中&#xff0c;经常会使用接口和抽象类进行代码设计。为了更好地了解代码结构和功能&#xff0c;我们需要快速查看一个接口的所有实现类。IntelliJ IDEA提供了一些方便的方法来实现这一目标。 1. 点击查看接口的实现子类 在IDEA中&#xff0c;你可以轻松地查看…

swagger 内容信息与代码不一致,已解决

ApiModel是Swagger中的常用到的注解&#xff0c;检查下信息错误的实体类的ApiModel的value值是否一致&#xff0c;应该是写错了&#xff0c;是不是张冠李戴了

STM32 TIM2重映射

STM32定时器 文章目录 STM32定时器[TOC](文章目录) 前言一、问题分析二、代码 前言 最近想弄一个多路输出PWM&#xff0c;但是发现TIM2不能用&#xff0c;根据手册也对它进行重映射了&#xff0c;但是还是不能用&#xff0c;用示波器发现驱动能力比较弱&#xff0c;然后禁用jt…

博途PLC PID仿真(单容水箱液位高度控制)

单容水箱和双荣水箱的微分方程和数值求解,可以参考下面文章链接: https://rxxw-control.blog.csdn.net/article/details/131139432https://rxxw-control.blog.csdn.net/article/details/131139432这篇博客我们利用欧拉求解器在PLC里完成单容水箱的数学建模。PLC也可以和MATL…

【笔记】【算法设计与分析 - 北航童咏昕教授】绪论

算法设计与分析 - 北航童咏昕教授 文章目录 算法的定义定义性质 算法的表示自然语言编程语言伪代码 算法的分析算法分析的原则渐近分析 算法的定义 定义 给定计算问题&#xff0c;算法是一系列良定义的计算步骤&#xff0c;逐一执行计算步骤即可得预期的输出。 性质 有穷性确…

运维07:堡垒机

什么是跳板机 跳板机就是一台服务器而已&#xff0c;运维人员在使用管理服务器的时候&#xff0c;必须先连接上跳板机&#xff0c;然后才能去操控内网中的服务器&#xff0c;才能登录到目标设备上进行维护和操作 开发小张 ---> 登录跳板机 ---> 再登录开发服务器 测试…

vue3 用xlsx 解决 excel 低版本office无法打开问题

需求背景解决思路解决效果将json导出为excel将table导为excel导出样式 需求背景 原使用 vue3-json-excel &#xff0c;导致在笔记本office环境下&#xff0c;出现兼容性问题 <vue3-json-excel class"export-btn" :fetch"excelGetList" :fields"js…

Aster实现一台电脑当两台使——副屏搭配键鼠

前言&#xff1a;笔者每年回家&#xff0c;都面临着想要和小伙伴一起玩游戏&#xff0c;但小伙伴没有电脑/只有低配电脑的问题。与此同时&#xff0c;笔者自身的电脑是高配置的电脑&#xff0c;因此笔者想到&#xff0c;能否在自己的电脑上运行游戏&#xff0c;在小伙伴的电脑上…

Code-Audit(代码审计)习题记录

介绍&#xff1a; 自己懒得搭建靶场了&#xff0c;靶场地址是 GitHub - CHYbeta/Code-Audit-Challenges: Code-Audit-Challenges为了方便在公网练习&#xff0c;可以随地访问&#xff0c;本文所有的题目均来源于网站HSCSEC-Code Audit 1、习题一 题目内容如下&#xff1a; 1…

2024pytest自动化测试框架学习(三)

在自动化测试中我们经常会针对某些测试方法编写前置测试数据&#xff0c;当测试方法执行完毕后再清理这些测试数据。之前我们接触的unittest框架中&#xff0c;使用setUp、tearDown方法来解决前置数据、后置数据销毁的问题。pytest为我们提供了更加强大灵活的fixtrue来完成该实…

《Solidity 简易速速上手小册》第8章:高级 Solidity 概念(2024 最新版)

文章目录 8.1 高级数据类型和结构8.1.1 基础知识解析更深入的理解实际操作技巧 8.1.2 重点案例&#xff1a;构建一个去中心化身份系统案例 Demo&#xff1a;创建去中心化身份系统案例代码DecentralizedIdentityContract.sol 测试和验证拓展案例 8.1.3 拓展案例 1&#xff1a;管…

MedicalGPT 训练医疗大模型,实现了包括增量预训练、有监督微调、RLHF(奖励建模、强化学习训练)和DPO(直接偏好优化)

MedicalGPT 训练医疗大模型&#xff0c;实现了包括增量预训练、有监督微调、RLHF(奖励建模、强化学习训练)和DPO(直接偏好优化)。 MedicalGPT: Training Your Own Medical GPT Model with ChatGPT Training Pipeline. 训练医疗大模型&#xff0c;实现了包括增量预训练、有监督微…