[WITACM选拔赛]B题和C题最短路前缀和+二分

Posted cls1277

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[WITACM选拔赛]B题和C题最短路前缀和+二分相关的知识,希望对你有一定的参考价值。

Pro

比赛是在牛客上训练的时候打的重现赛

链接在这:B题 C题

Sol

训练时:为什么就是做不对呢?我感觉思路没问题啊!

结束后:为什么一直错呢?明明思路都一模一样!

找到错后:woc!!!

B题:写了个bfs发现思路有大问题,因为bfs如果求最短路的话一定是第一个访问到的,但是本题第一个访问到的不一定最优。(写到这,突然想到一些东西,应该说朴素的bfs不可以,但是加上优先队列不知道可不可呢?)

B题正解:直接对每个点和周围的点连边,在传送门的两端连边(注意判断是否为陷阱),跑一遍最短路(dij堆优化模板)就好。

我错在哪了?因为是二维去转化成点的编号,应该是行号乘列数加列号!

C题:思路很简单,看到基本就想到了前缀和和二分,但是!就是WA(我太菜了

我错在哪了?首先w0一定是0,其实是一个n+1长度的数组,误以为n。发现这个错误后其实还没意识到排序的时候也是按照n个来排序的,所以继续在WA。事实上,只需要知道是n+1,然后把该改的地方改了就A了。

Code

B题

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#include<stack>
using namespace std;
typedef long long LL;
#define PI acos(-1)
#define INF 2147483647
#define eps 1e-7
#define Fo(i,a,b) for(LL i=(a); i<=(b); i++)
#define Ro(i,b,a) for(LL i=(b); i>=(a); i--)
#define Ms(a,b) memset((a),(b),sizeof(a))
#define lowbit(_) _&(-_)
inline LL read() {
	LL x = 0, f = 1;char c = getchar();
	while (!isdigit(c)) { if (c == '-')f = -f;c = getchar(); }
	while (isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48ll), c = getchar();
	return x * f;
}

#define MAXN 90005
struct Node {
	LL to , next , val;
};
Node e[MAXN*4+1005];
struct Seg {
	LL  x , y;
	Seg() {
		x=-1 , y=-1;
	};
	Seg(LL xx , LL yy) {
		x=xx , y=yy;
	}
}; 
vector<Seg>cq[305][305];
struct Que {
	LL len , num;
	Que(LL ll , LL nn) {
		len = ll , num = nn;
	}
};
LL tot , head[MAXN] , n , m , q , sx=-1 , sy=-1 , tx=-1 , ty=-1 , dis[MAXN]; 
string mp[305];

void add(LL x , LL y , LL z) {
	tot++;
	e[tot].to = y;
	e[tot].next = head[x];
	e[tot].val = z;
	head[x] = tot;
}

bool operator < (Que a , Que b) {
	return a.len > b.len;
}

void dij(LL s) {
	Fo(i,0,MAXN)
		dis[i] = INF;
	dis[s] = 0;
	priority_queue<Que>q;
	q.push(Que(0,s));
	while(!q.empty()) {
		Que u=q.top();
		q.pop();
		if(u.len!=dis[u.num]) continue;
		for(int i=head[u.num]; i;i=e[i].next) {
			LL v=e[i].to;
			if(dis[v]>dis[u.num]+e[i].val) {
				dis[v] = dis[u.num]+e[i].val;
				q.push(Que(dis[v] , v));
			}
		}
	}
}

int main() {
//	freopen("datad.txt","r",stdin);
	n=read(); m=read(); q=read();
	Fo(i,0,n-1) cin>>mp[i];
	Fo(i,1,q) {
		LL x1 , z1 , x2 , z2;
	//	x1=read(); z1=read(); x2=read(); z2=read();
		scanf("%lld%lld%lld%lld",&x1,&z1,&x2,&z2);
		cq[x1][z1].push_back(Seg(x2,z2));
		cq[x2][z2].push_back(Seg(x1,z1));
	}
	Fo(i,0,n-1) {
		Fo(j,0,m-1) {
			if(mp[i][j]=='#') continue;
			if(mp[i][j]=='S') {
				sx = i , sy = j;
			}
			if(mp[i][j]=='T') {
				tx = i , ty = j;
			}
			if(i-1>=0&&mp[i-1][j]!='#')
				add(i*m+j , (i-1)*m+j , 1);
			if(i+1<n&&mp[i+1][j]!='#')
				add(i*m+j , (i+1)*m+j , 1);
			if(j-1>=0&&mp[i][j-1]!='#')
				add(i*m+j , i*m+j-1 , 1);
			if(j+1<m&&mp[i][j+1]!='#')
				add(i*m+j , i*m+j+1 , 1);
			if(cq[i][j].size()!=0)
				Fo(k,0,cq[i][j].size()-1)
					if(mp[cq[i][j][k].x][cq[i][j][k].y]!='#')
						add(i*m+j , cq[i][j][k].x*m+cq[i][j][k].y , 3);	
		}
	}
	if((sx==-1&&sy==-1)&&(tx==-1&&ty==-1)) {
		printf("0");
		return 0;
	}
	if((sx==-1&&sy==-1)||(tx==-1&&ty==-1)) {
		printf("-1");
		return 0;
	}
	
	dij(sx*m+sy);
	if(dis[tx*m+ty]==INF)
		printf("-1");
	else
		printf("%lld",dis[tx*m+ty]);
	return 0;
}


C题

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#include<stack>
using namespace std;
typedef long long LL;
#define PI acos(-1)
#define INF 2147483647
#define eps 1e-7
#define Fo(i,a,b) for(LL i=(a); i<=(b); i++)
#define Ro(i,b,a) for(LL i=(b); i>=(a); i--)
#define Ms(a,b) memset((a),(b),sizeof(a))
#define lowbit(_) _&(-_)
inline LL read() {
	LL x = 0, f = 1;char c = getchar();
	while (!isdigit(c)) { if (c == '-')f = -f;c = getchar(); }
	while (isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48ll), c = getchar();
	return x * f;
}

#define MAXN 100005
struct Node {
	LL data , id;
	Node(){};
	Node(LL dd , LL ii) {
		data = dd , id = ii;
	}
	bool operator < (const Node &a) {
		return data<a.data;
	}
};
Node a[MAXN];
LL n , m , tt[MAXN] , ans;

struct cmp {
	bool operator() (const Node& s1,  const Node& s2) {
		return s1.data<s2.data;
	}
};

int main() {
//	freopen("data.txt","r",stdin);	
	n=read(); m=read();
	a[0].id = a[0].data = 0;
	Fo(i,1,n) {
		LL x = read();
		a[i].data = a[i-1].data + x;
		a[i].id = i;
	}
	sort(a , a+n+1);
	Fo(i,0,n)
		tt[i] = a[i].data;
	Fo(i,1,m) {
		LL k=read();
		LL pos = upper_bound(tt , tt+n+1 , k)-tt-1;
		LL sum = k-tt[pos];
		ans = a[pos].id;
		Ro(j,pos-1,0) {
			if(k-tt[j]!=sum)
				break;
			ans = max(ans , a[j].id);
		}
		printf("%lld\\n",ans);
	}
	return 0;
}

以上是关于[WITACM选拔赛]B题和C题最短路前缀和+二分的主要内容,如果未能解决你的问题,请参考以下文章

抛物线压轴题最短路径面积最值问题

比赛题解 更新ING

bzoj2653 -- 二分+主席树

P1462 通往奥格瑞玛的道路 (二分+最短路)

2019 CCPC - 网络选拔赛 D path(求第k短路)

CF978C Letters前缀和+二分查找/几房几号