并不对劲的素质四连(二)

为什么连续两天都中奖上去讲题?

d2t1

题意:后缀数组/哈希板子题

做法:后缀数组/哈希

d2t2

题意:T组数据,给n条线段,判断它们是否和某条线段有公共点,n<=10^4,T<=10,保证线段不是一个点

做法:可以先画这样一个图:

那么接下来就是要判断是否平行/共线/重合/交点在两线段上,设两线段为l1和l2,l1的两端点为A1和B1,l2的两端点为A2和B2

1.判断平行:

为了防止用小数存导致精度问题,可以把它们的斜率写成分数形式,设为a1/b1和a2/b2。会发现b1和b2可能为0,特判会很麻烦,而且分数还得化简。所以要交叉相乘,把式子变成判断a1*b2和a2*b1是否相等

2.在平行的条件下判断共线:

在l1上任取两点(或一点),在l2上任取一点(或两点),保证三点不重合,当且仅当l1和l2共线时,以它们三个组成的三角形面积为0。那么就可以直接判断l1的两端点和l2的一个端点围成的三角形面积是否为0

3.在共线的条件下判断重合:

当且仅当两条线段重合时,存在一个端点在另一条线段上。那么就可以判断四个端点是否在另一条线段上

3.判断不平行的两线段的交点是否都在两线段上:

如果A、B在直线l两侧,那么l和l的交点在AB上,对于A和B和l也同理。那么就可以用叉积求出有向面积,通过正负判断两点是否在一条直线两侧。

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<stack>
#include<set>
#include<queue>
#include<vector>
#define LL long long
using namespace std;
LL read()
{
	LL x=0,f=1;char ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-')f=-1,ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x*f;
}
void write(LL x)
{
	LL f=0;char ch[20];
	if(x==0){putchar('0'),putchar('\n');return;}
	if(x<0){putchar('-'),x=-x;}
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
}
typedef struct vect{LL x,y;}V;
typedef struct poin{LL x,y;}P;
typedef struct line{V v;P s,t;}L;
LL yesv(V x,V y){if((x.x==0&&x.y==0)||(y.x==0&&x.x==0))return 0;return (x.x==y.x&&x.y==y.y)?0:1;}
V make_v(LL x,LL y){V tmp;tmp.x=x,tmp.y=y;return tmp;}
P make_p(LL x,LL y){P tmp;tmp.x=x,tmp.y=y;return tmp;}
L make_l(V v,P s,P t){L tmp;tmp.v=v,tmp.s=s,tmp.t=t;return tmp;}
LL onl(P x,L y)
{
	LL maxx=max(y.s.x,y.t.x),maxy=max(y.s.y,y.t.y),minx=min(y.s.x,y.t.x),miny=min(y.s.y,y.t.y);
	if(x.x>=minx&&x.x<=maxx&&x.y>=miny&&x.y<=maxy)return 1;
	else return 0;
}
LL cros(P a,P b){return a.x*b.y-a.y*b.x;}
LL onv(L x,L y)
{
	if(!yesv(x.v,y.v)&&(cros(x.s,y.s)+cros(y.s,x.t)+cros(x.t,x.s)==0)&&(onl(x.s,y)||onl(x.t,y)||onl(y.s,x)||onl(y.t,x)))return 1;
	return 0;
}
LL sides(L x,L y)
{
	LL s1=cros(x.s,y.s)+cros(y.s,x.t)+cros(x.t,x.s),s2=cros(x.t,y.t)+cros(y.t,x.s)+cros(x.s,x.t);
	if(s1==0||s2==0)return 1;
	LL f=(((s1<0)^(s2<0))==0);
	if(f)return 1;
	return 0;
}
LL yesl(L a,L b)
{
	if(onv(a,b)){return 1;}
	if(!yesv(a.v,b.v)){return 0;}
	if(sides(a,b)&&sides(b,a)){return  1;}
	return 0;
}
LL n,T;
L a;
LL gcd(LL x,LL y)
{
	if(x>y)swap(x,y);
	if(x==0)return y;
	return gcd(y%x,x);
}
int main()
{
	freopen("intersect.in","r",stdin);
	freopen("intersect.out","w",stdout);
	T=read();
	while(T--)
	{
		n=read();
		LL xs=read(),ys=read(),xt=read(),yt=read();
		LL lx=xt-xs,ly=yt-ys,fx=(lx<0)?-1:1,fy=(ly<0)?-1:1;
		LL gdc=gcd(abs(lx),abs(ly));
		a=make_l(make_v(abs(lx)/gdc*fx,abs(ly)/gdc*fy),make_p(xs,ys),make_p(xt,yt));
		LL f=0;
		for(LL i=1;i<=n;i++)
		{
			LL xss=read(),yss=read(),xtt=read(),ytt=read();
			if(f)continue;
			LL lxx=xtt-xss,lyy=ytt-yss,fxx=(lxx<0)?-1:1,fyy=(lyy<0)?-1:1;
			LL gdcc=gcd(abs(lxx),abs(lyy));
			L b=make_l(make_v(abs(lxx)/gdcc*fxx,abs(lyy)/gdcc*fyy),make_p(xss,yss),make_p(xtt,ytt));
			if(!f)f|=yesl(a,b);
		}
		if(f)puts("YES");
		else puts("NO");
	}
	return 0;
}
/*
3
1
1 1 4 4
2 2 3 3
1
1 1 4 4
2 2 3 1
1
1 1 4 4
5 5 6 6
*/
/*
3
1
2 1 4 1
5 1 4 2
1
3 2 1 4
3 3 2 4
1
5 1 4 2
4 2 3 3
*/

  

d2t3

题意:有一个n个点,m条无向边的图,每条边有两个系数,c和w,表示经过该边要花c的能量,只有当能量大于等于w时才能够走这条边。问从1号点出发,至少携带多少能量才能走到n,n,m<=10^5,1<=c<=10^3,1<=w<=10^9

做法:dis[i]表示从编号为i的点出发,走到n最少需要多少能量。转移是dis[u]=min{max(w[k],dis[v[k]]+c[k])}。然而并不对劲的人dijkstra忘记改大根堆,非常难受。

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<stack>
#include<set>
#include<queue>
#include<vector>
#define maxn 100010
#define maxm 200010
#define pii pair<int ,int>
#define fi first
#define se second
using namespace std;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-')f=-1,ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x*f;
}
void write(int x)
{
	int f=0;char ch[20];
	if(x==0){putchar('0'),putchar('\n');return;}
	if(x<0){putchar('-'),x=-x;}
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
}
priority_queue<pii>q;
int dis[maxn],fir[maxn],nxt[maxm],v[maxm],c[maxm],w[maxm],vis[maxn],cnt,n,m;
void ade(int u1,int v1,int c1,int w1){v[cnt]=v1,w[cnt]=w1,c[cnt]=c1,nxt[cnt]=fir[u1],fir[u1]=cnt++;}
int main()
{
	freopen("spaceship2.in","r",stdin);
	freopen("spaceship2.out","w",stdout);
	memset(dis,0x7f,sizeof(dis));
	memset(fir,-1,sizeof(fir));
	n=read(),m=read();
	for(int i=1;i<=m;i++)
	{
		int a=read(),b=read(),c=read(),d=read();
		ade(a,b,c,d),ade(b,a,c,d);
	}
	dis[n]=0;q.push(make_pair(0,n));
	while(!q.empty())
	{
		int u=q.top().se;q.pop();
		if(vis[u])continue;vis[u]=1;
		for(int k=fir[u];k!=-1;k=nxt[k])
		{
			int now=max(w[k],c[k]+dis[u]);
			if(dis[v[k]]>now)
			{
				dis[v[k]]=now;
				q.push(make_pair(-now,v[k]));
			}
		}
	}
	if(dis[1]==dis[0])write(-1);
	else write(dis[1]);
	return 0;
}
/*
4 4
1 2 1 1
2 3 1 10
2 3 5 6
3 4 1 1
*/
/*
4 4
1 2 1 1
2 3 1 1
2 3 5 6
3 4 1 1
*/
/*
4 2
1 2 1 3
2 3 1 4
*/

  

猜你喜欢

转载自www.cnblogs.com/xzyf/p/9445180.html