zoukankan      html  css  js  c++  java
  • eJOI2017~2019

    ISIJ作业,所以来水了(

    说句闲话:tzc来水什么水

    UPD 2020.6.8:cnmd P6274是什么屑题啊/fn,都0202年了咋还有题考爆搜。。最后做吧,一晚上被这题毒害得什么也没干

    UPD 2020.7.2:时隔30+天,终于除了一个毒瘤eJOI2019E和计几eJOI2017C其他都做完了/lh。接下来补题解。

    eJOI2017

    A - Magic

    洛谷题目页面传送门

    给定字符串(a,|a|=n),字符集为(Sigma)。一个子串有魔法当且仅当它内部包含所有(Sigma)种字符,且所有种类的字符数量相等。求有魔法的非空子串数量。

    (ninleft[2,10^5 ight],|Sigma|in[1,52])

    首先预处理出对于每种字符(j)的前缀计数(Sum_{i,j})(mathrm O(n|Sigma|))

    探索充要条件:一个子串(a_{lsim r})有魔法显然当且仅当(forall iinSigma,Sum_{r,i}-Sum_{l-1,i}=dfrac{r-l+1}{|Sigma|}Leftrightarrow |Sigma|Sum_{r,i}-r=|Sigma|Sum_{l-1,i}-(l-1))。设(b_{i,j}=|Sigma|Sum_{i,j}-i),把(b_i)看成一个(|Sigma|)元组,则上面那个充要条件即(b_{l-1}=b_r)。只要从左往右扫一遍,扫到(i)时,将多重集中(b_i)的数量贡献进答案,再将(b_i)扔进多重集即可。multisetcount()函数复杂度是线性的,可以用map实现多重集,(mathrm O(n|Sigma|)+mathrm O(n|Sigma|log n)=mathrm O(n|Sigma|log n))。当然,这个(b_i)可以哈希,然后用哈希表实现多重集,这样扫描部分的时间复杂度为(mathrm O(n));前缀计数预处理部分也可以改为一边扫描一边线段树维护,(mathrm O(nlog k))。不过既然蒟蒻没有被卡常,就不写那么复杂了吧~

    最后,蒟蒻忘记取模了,模数又抄错了(2)次,交了好几发才过……已加入sb错误列表(第(4)条)(

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    const int mod=1000000007;
    const int N=100000,LET=52,ASCII=150;
    int n;
    char a[N+5];
    vector<char> sigma;//字符集 
    int pos[ASCII];//字符对应在sigma里的下标 
    int Sum[N+1][LET];//前缀计数 
    map<vector<int>,int> mp;//多重集 
    int main(){
    //	freopen("C:\Users\chenx\Downloads\P6273_12.in","r",stdin);
    	cin>>n>>a+1;
    	for(int i=1;i<=n;i++)sigma.pb(a[i]); 
    	sort(sigma.begin(),sigma.end());
    	sigma.resize(unique(sigma.begin(),sigma.end())-sigma.begin());//预处理sigma 
    	for(int i=0;i<sigma.size();i++)pos[sigma[i]]=i;//预处理pos 
    	int ans=0;
    	mp[vector<int>(sigma.size(),0)]=1;//b[0] 
    	for(int i=1;i<=n;i++){//扫描 
    		for(int j=0;j<sigma.size();j++)Sum[i][j]=Sum[i-1][j];//计算前缀计数 
    		Sum[i][pos[a[i]]]++;
    		vector<int> v;//b[i]
    		for(int j=0;j<sigma.size();j++)v.pb(sigma.size()*Sum[i][j]-i);
    		(ans+=mp[v]++)%=mod;//贡献答案 
    	}
    	cout<<ans;
    	return 0;
    }
    

    E - Experience

    洛谷题目页面传送门

    给定大小为(n)的树,(1)为根,每个点(i)有权值(a_i)。要求将整棵树分成若干条直链,最大化所有直链中权值组成的集合的极差之和。输出最大值。

    (ninleft[1,10^5 ight])

    不难发现一个很好的性质:若一条直链不是从上到下严格单调递增或严格单调递减的,那么一定可以从它打破单调性处割开,使总极差不减。也就是说,最大化极差之和的剖法中一定是每条直链都是严格单调的。

    接下来可以愉快地树形DP了。设(dp_{i,j}(jin{0,1}))表示子树(i)内,包含(i)的直链的单调方向为(j)时的最大极差和。转移就是,先让(i)自己一个人组成一条直链,再往每个符合单调性的儿子转移,其他儿子原封不动地加到结果里。很简单。

    答案是(max(dp_{1,0},dp_{1,1}))

    时间复杂度(mathrm O(n))

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define pb push_back
    const int N=100000;
    int n;
    int a[N+1];
    vector<int> son[N+1];
    int dp1[N+1]/*dp[i][0]*/,dp2[N+1]/*dp[i][1]*/;
    void dfs(int x=1){
    	int sum=0;
    	for(int i=0;i<son[x].size();i++){
    		int y=son[x][i];
    		dfs(y);
    		sum+=max(dp1[y],dp2[y]);
    	}
    	dp1[x]=dp2[x]=sum;//x一个人 
    	for(int i=0;i<son[x].size();i++){
    		int y=son[x][i];
    		if(a[y]<a[x])/*单调类型1*/dp1[x]=max(dp1[x],dp1[y]+a[x]-a[y]+sum-max(dp1[y],dp2[y]));
    		else if(a[y]>a[x])/*单调类型2*/dp2[x]=max(dp2[x],dp2[y]+a[y]-a[x]+sum-max(dp1[y],dp2[y]));
    	}
    //	printf("dp[%lld]=(%lld,%lld)
    ",x,dp1[x],dp2[x]);
    }
    signed main(){
    	cin>>n;
    	for(int i=1;i<=n;i++)scanf("%lld",a+i);
    	for(int i=1;i<n;i++){
    		int x,y;
    		scanf("%lld%lld",&x,&y);
    		son[x].pb(y);
    	}
    	dfs();//DP 
    	cout<<max(dp1[1],dp2[1]);
    	return 0;
    }
    

    F - Game

    洛谷题目页面传送门

    题意见洛谷。

    首先有个显然的贪心:任何一个人都会取当前(S)中最大的数。然后就转化成了一个类似DS题的问题?

    就是要往集合里加数、取最大数、加数、取最大数、……、加数、取最大数、取最大数、取最大数、取最大数……、取最大数。不难想到堆,但那会T飞。注意到加完数之后立刻会取数这个很好的性质。我们可以维护每个数出现的次数,并且实时维护当前最大值(now)。若加的数(x>now),则下一个取的数肯定是(x);否则将(x)的出现次数(+1),并将(now)往前two-pointers。如此一来,时间线性。

    代码(加了洛谷自带O2才能过,人傻常数大/kel):

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=100000;
    int n,m;
    int a[N+1];
    int buc[N+1];//出现次数 
    signed main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++)scanf("%lld",a+i);
    	while(m--){
    		int x;
    		scanf("%lld",&x);
    		memset(buc,0,sizeof(buc));
    		int now=n,ans=0,player=1/*当前是谁取*/;
    		for(int i=1;i<=x;i++)buc[a[i]]++;
    		while(!buc[now])now--;//two-pointers 
    		ans+=player*now;buc[now]--;player*=-1;
    		for(int i=x+1;i<=n;i++){
    			if(a[i]>=now)ans+=player*a[i],player*=-1;//直接去a[i] 
    			else{//将a[i]扔进桶并two-pointers 
    				buc[a[i]]++;
    				while(!buc[now])now--;
    				ans+=player*now;buc[now]--;player*=-1;
    			}
    		}
    		while(--x){//剩下来的没有加数了 
    			while(!buc[now])now--;
    			ans+=player*now;buc[now]--;player*=-1;
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

    eJOI2018

    A - Hills

    洛谷题目页面传送门

    题意见洛谷。

    比较简单的DP。看到数据范围,基本可以确定时间复杂度(mathrm O!left(n^2 ight))。于是(2)维确定了:考虑到的位置((in[0,n]))、建房子的山数((inleft[0,leftlceildfrac n2 ight ceil ight]))。由于距离为(2)(2)个建房子的山共享一个相邻山,情况需要特判,所以记录当前考虑的山们中倒数(2)个的建房子情况,即状态为(dp_{i,j,k,o}),其中((k,o)in{(0,0),(0,1),(1,0)})((1,1))不行,因为相邻(2)座山不可能都建房子)。边界(dp_{0,j,k,o}=egin{cases}0&j=k=o=0\+infty& ext{otherwise}end{cases}),目标(forall jinleft[1,leftlceildfrac n2 ight ceil ight],min(dp_{n,j,0,0},dp_{n,j,0,1},dp_{n,j,1,0}))。状态转移方程有点长不想列了/doge,注意一下(k=0,o=1)时要提前算第(i+1)座山要挖的时间,如果倒数第(3)座山建房子的话要撤销当时提前算的倒数第(2)座山要挖的时间,改成这(2)座建房子的山左右夹击时倒数第(2)座山要挖的时间。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5000;
    int n;
    int a[N+2];
    int dp[N+1][N/2+1][2][2]; 
    int main(){
    	cin>>n;
    	for(int i=1;i<=n;i++)cin>>a[i];
    	memset(dp,0x3f,sizeof(dp));
    	dp[0][0][0][0]=0;//边界 
    	for(int i=1;i<=n;i++)for(int j=0;j<=n+1>>1;j++){//转移 
    		dp[i][j][0][0]=min(dp[i-1][j][0][0],dp[i-1][j][1][0]);
    		if(j){
    			dp[i][j][0][1]=dp[i-1][j-1][0][0]+max(0,a[i-1]-(a[i]-1))+max(0,a[i+1]-(a[i]-1));
    //			cout<<dp[i-1][j-1][0][0]<<" "<<max(0,a[i-1]-(a[i]-1))<<" "<<max(0,a[i+1]-(a[i]-1))<<" "<<dp[i][j][0][1]<<"
    ";
    			if(i>2)dp[i][j][0][1]=min(dp[i][j][0][1],dp[i-1][j-1][1][0]+max(0,a[i-1]-(min(a[i],a[i-2])-1))-max(0,a[i-1]-(a[i-2]-1))+max(0,a[i+1]-(a[i]-1)));
    //			cout<<dp[i][j][0][1]<<"
    ";
    		}
    		dp[i][j][1][0]=dp[i-1][j][0][1];
    //		printf("dp[%d][%d]=%d %d %d
    ",i,j,dp[i][j][0][0],dp[i][j][0][1],dp[i][j][1][0]);
    	}
    	for(int i=1;i<=n+1>>1;i++)cout<<min(min(dp[n][i][0][0],dp[n][i][0][1]),dp[n][i][1][0])<<" ";//目标 
    	return 0;
    }
    

    D - Chemical table

    洛谷题目页面传送门

    题意见洛谷。

    一眼就是个图论题。(咋是个紫题嘞)

    考虑所有已有的元素张成的元素空间长啥样。显然,对于任意两行(a,b),若存在(c)使得位置((a,c),(b,c))都有元素的话,那么(a,b)两行生死与共,即张成空间中(a,b)两行经过上下平移可以重合。(自证不难)

    考虑基于行建图,将所有生死与共对连接起来,可以得到一些CC(连边操作可以对于每一列(c),将所有该行(c)列有元素的行们连接起来,从左到右线性连接即可保证连通性,不必连成完全图)。我们最后的目标是填一些元素使得张成空间为元素全集,此时显然等价于所有行生死与共,并且有元素的列集合为列全集。分别解决即可。

    “所有行生死与共”:建图,DFS,答案为CC数量(-1);“有元素的列集合为列全集”:答案为(m)减去有元素的列集合的大小。最终答案为两个答案加起来。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    const int N=200000,M=200000;
    int n,m,s;
    vector<int> bel[M+1],nei[N+1];
    bool vis[N+1];
    void dfs(int x){//DFS求CC 
    	vis[x]=true;
    	for(int i=0;i<nei[x].size();i++){
    		int y=nei[x][i];
    		if(!vis[y])dfs(y);
    	}
    }
    int main(){
    	cin>>n>>m>>s;
    	while(s--){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		bel[y].pb(x);
    	}
    	int ans=-1;
    	for(int i=1;i<=m;i++){
    		ans+=bel[i].empty();//子任务2 
    		for(int j=0;j+1<bel[i].size();j++)nei[bel[i][j]].pb(bel[i][j+1]),nei[bel[i][j+1]].pb(bel[i][j]);
    	}//建图 
    	for(int i=1;i<=n;i++)if(!vis[i])ans++,dfs(i);//子任务1 
    	cout<<ans;
    	return 0;
    }
    

    eJOI2019

    A - XORanges

    洛谷题目页面传送门

    给定(n)个自然数,第(i)个为(a_i),支持(2)(q)次操作:

    1. ( exttt1 x v):令(a_x=v)
    2. ( exttt2 l r):求区间([l,r])的所有子区间的异或和的异或和。

    (n,qinleft[1,2 imes10^5 ight])

    咋异或完粽子又来异或橙子/yiw

    对于操作( exttt2),考虑算贡献法,即考虑([l,r])内所有数被异或进答案多少次。由于是异或,偶数次相当于没有,奇数次相当于(1)次。分成(2)种情况:

    1. (lmod2=rmod2):此时(a_i)会被算((i-l+1)(r-i+1))次。因为(l,r)奇偶性相同,所以(i-l+1,r-i+1)奇偶性相同,那么((i-l+1)(r-i+1))是奇数当且仅当(imod2=lmod2)。由于还有单点修改操作,只需维护一个BIT,里面分别维护位置奇、偶(2)种的区间异或和即可;
    2. (lmod2 eq rmod2):此时(a_i)依然会被算((i-l+1)(r-i+1))次。因为(l,r)奇偶性不同,所以(i-l+1,r-i+1)奇偶性不同,一奇一偶,乘积肯定偶,所以答案为(0)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int lowbit(int x){return x&-x;}
    const int N=200000;
    int n,qu;
    int a[N+1];
    struct bitree{//BIT 
    	int xsm[N+1][2];//2种异或和 
    	void init(){//预处理 
    		static int Xsm[N+1][2]={};
    		for(int i=1;i<=n;i++){
    			Xsm[i][0]=Xsm[i-1][0];Xsm[i][1]=Xsm[i-1][1];
    			Xsm[i][i&1]^=a[i];
    			xsm[i][0]=Xsm[i][0]^Xsm[i-lowbit(i)][0];xsm[i][1]=Xsm[i][1]^Xsm[i-lowbit(i)][1];
    		}
    	}
    	void chg(int x,int v){//单点修改 
    		int p=x;
    		while(x<=n)xsm[x][p&1]^=a[p]^v,x+=lowbit(x);
    		a[p]=v;
    	}
    	int Xsm(int x,int p){//前缀异或和 
    		int res=0;
    		while(x)res^=xsm[x][p&1],x-=lowbit(x);
    		return res;
    	}
    	int _xsm(int l,int r){return Xsm(r,l&1)^Xsm(l-1,l&1);}//区间异或和 
    }bit;
    int main(){
    	cin>>n>>qu;
    	for(int i=1;i<=n;i++)cin>>a[i];
    	bit.init();//BIT初始化 
    	while(qu--){
    		int tp,x,y;
    		cin>>tp>>x>>y;
    		if(tp==1)bit.chg(x,y);
    		else{
    			if((x&1)==(y&1))cout<<bit._xsm(x,y)<<"
    ";
    			else puts("0");
    		}
    	}
    	return 0;
    }
    

    B - Hanging Rack

    洛谷题目页面传送门

    题意见洛谷。(用(m)表示题目中的(k)

    观察样例+冷静思考可以得出一个结论:第(i(imod2=1))次的挂钩往右平移(2^{n-1})格就是第(i+1)次的挂钩。理由很显然,因为要保持最上面的那个连接杆平衡。这样一来,就可以将原问题转化为一个规模减(1)的问题,大概是这样的:

    if(m%2==1)n--,(m+=1)>>=1;
    else n--,m>>=1,(ans+=pw[n])%=mod;
    

    其中pw[i](2^i)。直到(n=0)为止。初始时(ans=1)

    预处理(pw),复杂度(mathrm O(n))

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int mod=1000000007;
    const int N=1000000;
    int pw[N+1];
    signed main(){
    	int n,m;
    	cin>>n>>m;
    	pw[0]=1;
    	for(int i=1;i<=n;i++)pw[i]=(pw[i-1]<<1)%mod;
    	int ans=1;
    	while(n){
    		if(m%2==1)n--,(m+=1)>>=1;
    		else n--,m>>=1,(ans+=pw[n])%=mod;
    	}
    	cout<<ans;
    	return 0;
    }
    

    D - Tower

    洛谷题目页面传送门

    有一个塔,从下往上数层数,初始有(1)层数字为(1)。每步可以选择已有的所有数字中([l,r])层内所有的数字,计算它们的和并放在塔顶。给定(n),求最少需要多少步能构造出塔顶为(n)的塔,并给出方案(每次的(l,r))。本题多测。

    (ninleft[1,10^{18} ight])

    既然要算最少多少步,不妨先算出步数的下限。每步都尽可能让塔顶大,即每步都选塔内所有数相加,这样第(1)步得(1),以后每步翻倍,这样至少需要(ans=lceillog_2n ceil+1)步塔顶才能(geq n)

    考虑尽可能逼近下限。我们先这样丧心病狂地每步最大化塔顶地建出一个塔,显然长这个样子:第(i(igeq2))层为(2^{i-2})。此时塔顶是(geq n)的,考虑减少一些塔内的数字使得塔顶(=n)。显然(iin[3,ans]),都可以令第(i)步的(l)由原来的(1)变成(2),这样第(i)层减少(1),产生连锁反应,第(i+1)层减少(1),第(i+2)层减少(2),……,第(i+x)层减少(2^{x-1}),于是塔顶减少(2^{ans-i})(left{2^{ans-i}mid iin[3,ans] ight}=left{2^{i}mid iin[0,ans-3] ight})。再考虑一共需要减少多少。显然(2^{ans-1}-n<2^{ans-1}),又(n)二进制下最高位一定为(1),则(2^{ans-1}-n<2^{ans-2})。那么将它二进制分解,用集合(left{2^{i}mid iin[0,ans-3] ight})恰好永远存在方案凑出来。也就是说下限(ans)达得到。于是这题就做完了(这不是某数学老师hzj的名言么)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    void mian(){
    	int n;
    	cin>>n;
    	int ans=0;
    	while(1ll<<ans<n)ans++;
    	ans++;
    	cout<<ans<<"
    1 1
    ";//第1步 
    	for(int i=ans-1;i>=2;i--)
    		printf("%lld %lld
    ",1ll+!!((1ll<<ans-1)-n&1ll<<i-2),ans-i+1);//凑 
    	cout<<"1 "<<ans<<"
    ";//塔顶 
    }
    signed main(){
    	int testnum;
    	cin>>testnum;
    	while(testnum--)mian();
    	return 0;
    }
    

    F - Awesome Arrowland Adventure

    洛谷题目页面传送门

    题意见洛谷。

    看到这种网格题,就想DP,结果发现有环,果断最短路。

    考虑对于每两个相邻网格有序对(((a,b),(c,d))),若((a,b))处有箭头,那么从((a,b))((c,d))连一条有向边,边权为从((a,b))的初始箭头方向到((a,b) o(c,d))应该的方向需要转的次数。然后堆优化Dijkstra即可。(mathrm O(nmlog nm))

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define y0 sdfjaewjfwa
    #define mp make_pair
    #define X first
    #define Y second
    #define pb push_back
    const int inf=0x3f3f3f3f;
    const int N=500,M=500,ASCII=150;
    int n,m;
    char a[N+1][M+5];
    int id[ASCII];const int ds[][4]={{0,1,2,3},{3,0,1,2},{2,3,0,1},{1,2,3,0}}/*方向与方向之间的距离*/,dx[]={-1,0,1,0},dy[]={0,1,0,-1};
    bool vld(int x,int y){return 1<=x&&x<=n&&1<=y&&y<=m;}
    vector<pair<int,int> > nei[N*M+1];//邻接矩阵 
    int dis[N*M+1];
    void dijkstra(){//Dijkstra
    	priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
    	memset(dis,0x3f,sizeof(dis));
    	q.push(mp(dis[1]=0,1));
    	while(q.size()){
    		int x=q.top().Y;
    		q.pop();
    		for(int i=0;i<nei[x].size();i++){
    			int y=nei[x][i].X,len=nei[x][i].Y;
    			if(dis[x]+len<dis[y])q.push(mp(dis[y]=dis[x]+len,y));
    		}
    	}
    //	for(int i=1;i<=n*m;i++)cout<<dis[i]<<" ";puts("");
    }
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++)cin>>a[i]+1;
    	id['N']=0;id['E']=1;id['S']=2;id['W']=3;
    	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(a[i][j]!='X')//连边 
    		for(int k=0;k<4;k++){
    			int x=i+dx[k],y=j+dy[k];
    			if(vld(x,y))nei[(i-1)*m+j].pb(mp((x-1)*m+y,ds[id[a[i][j]]][k]));
    		}
    	dijkstra();//求最短路 
    	cout<<(dis[n*m]<inf?dis[n*m]:-1);
    	return 0;
    }
    

    然后看到神仙ymx的题解,发现有(mathrm O(nm))的做法(orzymxtqlddw)。这里需要用到一个小trick。对于一个边权只有(0,1)两种的图求最短路时,我们可以把Dijkstra里的堆换成双端队列,松弛成功时若连接边为(0)则从队首加入,否则从队尾加入,正确性显然。就去掉了(log)。至于这题,可以将每个格子拆成(4)个点,每个点代表一个方向,方向到方向之间连(1)边,相邻格子之间连(0)边,然后跑上述trick即可。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define y0 sdfjaewjfwa
    #define mp make_pair
    #define X first
    #define Y second
    #define pb push_back
    #define pf push_front
    #define ppf pop_front
    const int inf=0x3f3f3f3f;
    const int N=500,M=500,ASCII=150;
    int n,m;
    char a[N+1][M+5];
    int id[ASCII];const int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
    bool vld(int x,int y){return 1<=x&&x<=n&&1<=y&&y<=m;}
    vector<pair<int,bool> > nei[4*N*M+1];//邻接矩阵 
    int dis[4*N*M+1];
    void dijkstra(){//Dijkstra 
    	deque<int> q;//双端队列 
    	memset(dis,0x3f,sizeof(dis));
    	dis[4-id[a[1][1]]]=0;q.pb(4-id[a[1][1]]);
    	while(q.size()){
    		int x=q[0];
    		q.ppf();
    		for(int i=0;i<nei[x].size();i++){
    			int y=nei[x][i].X;bool len=nei[x][i].Y;
    			if(dis[x]+len<dis[y]){
    				dis[y]=dis[x]+len;
    				if(len)q.pb(y);//队尾加 
    				else q.pf(y);//队首加 
    			}
    		}
    	}
    //	for(int i=1;i<=4*n*m;i++)cout<<dis[i]<<" ";puts("");
    }
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++)cin>>a[i]+1;
    	id['N']=0;id['E']=1;id['S']=2;id['W']=3;id['X']=0;
    	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(a[i][j]!='X')//连边 
    		for(int k=0;k<4;k++){
    			int x=i+dx[k],y=j+dy[k];
    			nei[4*((i-1)*m+j)-k].pb(mp(4*((i-1)*m+j)-(k+1)%4,1));
    			if(vld(x,y))nei[4*((i-1)*m+j)-k].pb(mp(4*((x-1)*m+y)-id[a[x][y]],0));
    		}
    	dijkstra();//求最短路 
    	cout<<(dis[4*n*m-id[a[n][m]]]<inf?dis[4*n*m-id[a[n][m]]]:-1);
    	return 0;
    }
    
  • 相关阅读:
    数据可视化
    numpy知识点
    机器学习之支持向量机
    python中字符编码及unicode和utf-8区别
    hihocoder图像算子(高斯消元)
    scrapy
    线性规划问题求解(单纯形法)
    机器学习之隐含马尔可夫
    机器学习之决策树
    机器学习之逻辑回归与最大熵模型
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/eJOI2017-2019.html
Copyright © 2011-2022 走看看