牛客小白月赛24题解 A-J

A最短路  几何

大佬几何模板

牛客小白月赛24题解 A-J_第1张图片

求出sum角,

求A,B 角, C角

得直线A-D1  直线B-D2  弧线D1-D2  相加即可

#include 
using namespace std;
// `计算几何模板`
const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxp = 1010;
//`Compares a double to zero`
int sgn(double x){
	if(fabs(x) < eps)return 0;
	if(x < 0)return -1;
	else return 1;
}
//square of a double
inline double sqr(double x){return x*x;}

struct Point{
	double x,y;
	Point(){}
	Point(double _x,double _y){
		x = _x;
		y = _y;
	}
	void input(){
		scanf("%lf%lf",&x,&y);
	}
	void output(){
		printf("%.2f %.2f\n",x,y);
	}
	bool operator == (Point b)const{
		return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;
	}
	bool operator < (Point b)const{
		return sgn(x-b.x)== 0?sgn(y-b.y)<0:x 0)return 2;
		else return 3;
	}
	// 点在线段上的判断
	bool pointonseg(Point p){
		return sgn((p-s)^(e-s)) == 0 && sgn((p-s)*(p-e)) <= 0;
	}
	//`两向量平行(对应直线平行或重合)`
	bool parallel(Line v){
		return sgn((e-s)^(v.e-v.s)) == 0;
	}
	//`两线段相交判断`
	//`2 规范相交`
	//`1 非规范相交`
	//`0 不相交`
	int segcrossseg(Line v){
		int d1 = sgn((e-s)^(v.s-s));
		int d2 = sgn((e-s)^(v.e-s));
		int d3 = sgn((v.e-v.s)^(s-v.s));
		int d4 = sgn((v.e-v.s)^(e-v.s));
		if( (d1^d2)==-2 && (d3^d4)==-2 )return 2;
		return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) ||
			(d2==0 && sgn((v.e-s)*(v.e-e))<=0) ||
			(d3==0 && sgn((s-v.s)*(s-v.e))<=0) ||
			(d4==0 && sgn((e-v.s)*(e-v.e))<=0);
	}
	//`直线和线段相交判断`
	//`-*this line   -v seg`
	//`2 规范相交`
	//`1 非规范相交`
	//`0 不相交`
	int linecrossseg(Line v){
		int d1 = sgn((e-s)^(v.s-s));
		int d2 = sgn((e-s)^(v.e-s));
		if((d1^d2)==-2) return 2;
		return (d1==0||d2==0);
	}
	//`两直线关系`
	//`0 平行`
	//`1 重合`
	//`2 相交`
	int linecrossline(Line v){
		if((*this).parallel(v))
			return v.relation(s)==3;
		return 2;
	}
	//`求两直线的交点`
	//`要保证两直线不平行或重合`
	Point crosspoint(Line v){
		double a1 = (v.e-v.s)^(s-v.s);
		double a2 = (v.e-v.s)^(e-v.s);
		return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
	}
	//点到直线的距离
	double dispointtoline(Point p){
		return fabs((p-s)^(e-s))/length();
	}
	//点到线段的距离
	double dispointtoseg(Point p){
		if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)
			return min(p.distance(s),p.distance(e));
		return dispointtoline(p);
	}
	//`返回线段到线段的距离`
	//`前提是两线段不相交,相交距离就是0了`
	double dissegtoseg(Line v){
		return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e)));
	}
	//`返回点p在直线上的投影`
	Point lineprog(Point p){
		return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2()) );
	}
	//`返回点p关于直线的对称点`
	Point symmetrypoint(Point p){
		Point q = lineprog(p);
		return Point(2*q.x-p.x,2*q.y-p.y);
	}
};
//圆
struct circle{
	Point p;//圆心
	double r;//半径
	circle(){}
	circle(Point _p,double _r){
		p = _p;
		r = _r;
	}
	circle(double x,double y,double _r){
		p = Point(x,y);
		r = _r;
	}
	//`三角形的外接圆`
	//`需要Point的+ /  rotate()  以及Line的crosspoint()`
	//`利用两条边的中垂线得到圆心`
	//`测试:UVA12304`
	circle(Point a,Point b,Point c){
		Line u = Line((a+b)/2,((a+b)/2)+((b-a).rotleft()));
		Line v = Line((b+c)/2,((b+c)/2)+((c-b).rotleft()));
		p = u.crosspoint(v);
		r = p.distance(a);
	}
	//`三角形的内切圆`
	//`参数bool t没有作用,只是为了和上面外接圆函数区别`
	//`测试:UVA12304`
	circle(Point a,Point b,Point c,bool t){
		Line u,v;
		double m = atan2(b.y-a.y,b.x-a.x), n = atan2(c.y-a.y,c.x-a.x);
		u.s = a;
		u.e = u.s + Point(cos((n+m)/2),sin((n+m)/2));
		v.s = b;
		m = atan2(a.y-b.y,a.x-b.x) , n = atan2(c.y-b.y,c.x-b.x);
		v.e = v.s + Point(cos((n+m)/2),sin((n+m)/2));
		p = u.crosspoint(v);
		r = Line(a,b).dispointtoseg(p);
	}
	//输入
	void input(){
		p.input();
		scanf("%lf",&r);
	}
	//输出
	void output(){
		printf("%.2lf %.2lf %.2lf\n",p.x,p.y,r);
	}
	bool operator == (circle v){
		return (p==v.p) && sgn(r-v.r)==0;
	}
	bool operator < (circle v)const{
		return ((p 0)return 5;
		if(sgn(d-r-v.r) == 0)return 4;
		double l = fabs(r-v.r);
		if(sgn(d-r-v.r)<0 && sgn(d-l)>0)return 3;
		if(sgn(d-l)==0)return 2;
		if(sgn(d-l)<0)return 1;
	}
	//`求两个圆的交点,返回0表示没有交点,返回1是一个交点,2是两个交点`
	//`需要relationcircle`
	//`测试:UVA12304`
	int pointcrosscircle(circle v,Point &p1,Point &p2){
		int rel = relationcircle(v);
		if(rel == 1 || rel == 5)return 0;
		double d = p.distance(v.p);
		double l = (d*d+r*r-v.r*v.r)/(2*d);
		double h = sqrt(r*r-l*l);
		Point tmp = p + (v.p-p).trunc(l);
		p1 = tmp + ((v.p-p).rotleft().trunc(h));
		p2 = tmp + ((v.p-p).rotright().trunc(h));
		if(rel == 2 || rel == 4)
			return 1;
		return 2;
	}
	//`求直线和圆的交点,返回交点个数`
	int pointcrossline(Line v,Point &p1,Point &p2){
		if(!(*this).relationline(v))return 0;
		Point a = v.lineprog(p);
		double d = v.dispointtoline(p);
		d = sqrt(r*r-d*d);
		if(sgn(d) == 0){
			p1 = a;
			p2 = a;
			return 1;
		}
		p1 = a + (v.e-v.s).trunc(d);
		p2 = a - (v.e-v.s).trunc(d);
		return 2;
	}
	//`得到过a,b两点,半径为r1的两个圆`
	int gercircle(Point a,Point b,double r1,circle &c1,circle &c2){
		circle x(a,r1),y(b,r1);
		int t = x.pointcrosscircle(y,c1.p,c2.p);
		if(!t)return 0;
		c1.r = c2.r = r;
		return t;
	}
	//`得到与直线u相切,过点q,半径为r1的圆`
	//`测试:UVA12304`
	int getcircle(Line u,Point q,double r1,circle &c1,circle &c2){
		double dis = u.dispointtoline(q);
		if(sgn(dis-r1*2)>0)return 0;
		if(sgn(dis) == 0){
			c1.p = q + ((u.e-u.s).rotleft().trunc(r1));
			c2.p = q + ((u.e-u.s).rotright().trunc(r1));
			c1.r = c2.r = r1;
			return 2;
		}
		Line u1 = Line((u.s + (u.e-u.s).rotleft().trunc(r1)),(u.e + (u.e-u.s).rotleft().trunc(r1)));
		Line u2 = Line((u.s + (u.e-u.s).rotright().trunc(r1)),(u.e + (u.e-u.s).rotright().trunc(r1)));
		circle cc = circle(q,r1);
		Point p1,p2;
		if(!cc.pointcrossline(u1,p1,p2))cc.pointcrossline(u2,p1,p2);
		c1 = circle(p1,r1);
		if(p1 == p2){
			c2 = c1;
			return 1;
		}
		c2 = circle(p2,r1);
		return 2;
	}
	//`同时与直线u,v相切,半径为r1的圆`
	//`测试:UVA12304`
	int getcircle(Line u,Line v,double r1,circle &c1,circle &c2,circle &c3,circle &c4){
		if(u.parallel(v))return 0;//两直线平行
		Line u1 = Line(u.s + (u.e-u.s).rotleft().trunc(r1),u.e + (u.e-u.s).rotleft().trunc(r1));
		Line u2 = Line(u.s + (u.e-u.s).rotright().trunc(r1),u.e + (u.e-u.s).rotright().trunc(r1));
		Line v1 = Line(v.s + (v.e-v.s).rotleft().trunc(r1),v.e + (v.e-v.s).rotleft().trunc(r1));
		Line v2 = Line(v.s + (v.e-v.s).rotright().trunc(r1),v.e + (v.e-v.s).rotright().trunc(r1));
		c1.r = c2.r = c3.r = c4.r = r1;
		c1.p = u1.crosspoint(v1);
		c2.p = u1.crosspoint(v2);
		c3.p = u2.crosspoint(v1);
		c4.p = u2.crosspoint(v2);
		return 4;
	}
	//`同时与不相交圆cx,cy相切,半径为r1的圆`
	//`测试:UVA12304`
	int getcircle(circle cx,circle cy,double r1,circle &c1,circle &c2){
		circle x(cx.p,r1+cx.r),y(cy.p,r1+cy.r);
		int t = x.pointcrosscircle(y,c1.p,c2.p);
		if(!t)return 0;
		c1.r = c2.r = r1;
		return t;
	}

	//`过一点作圆的切线(先判断点和圆的关系)`
	//`测试:UVA12304`
	int tangentline(Point q,Line &u,Line &v){
		int x = relation(q);
		if(x == 2)return 0;
		if(x == 1){
			u = Line(q,q + (q-p).rotleft());
			v = u;
			return 1;
		}
		double d = p.distance(q);
		double l = r*r/d;
		double h = sqrt(r*r-l*l);
		u = Line(q,p + ((q-p).trunc(l) + (q-p).rotleft().trunc(h)));
		v = Line(q,p + ((q-p).trunc(l) + (q-p).rotright().trunc(h)));
		return 2;
	}
	//`求两圆相交的面积`
	double areacircle(circle v){
		int rel = relationcircle(v);
		if(rel >= 4)return 0.0;
		if(rel <= 2)return min(area(),v.area());
		double d = p.distance(v.p);
		double hf = (r+v.r+d)/2.0;
		double ss = 2*sqrt(hf*(hf-r)*(hf-v.r)*(hf-d));
		double a1 = acos((r*r+d*d-v.r*v.r)/(2.0*r*d));
		a1 = a1*r*r;
		double a2 = acos((v.r*v.r+d*d-r*r)/(2.0*v.r*d));
		a2 = a2*v.r*v.r;
		return a1+a2-ss;
	}
	//`求圆和三角形pab的相交面积`
	//`测试:POJ3675 HDU3982 HDU2892`
	double areatriangle(Point a,Point b){
		if(sgn((p-a)^(p-b)) == 0)return 0.0;
		Point q[5];
		int len = 0;
		q[len++] = a;
		Line l(a,b);
		Point p1,p2;
		if(pointcrossline(l,q[1],q[2])==2){
			if(sgn((a-q[1])*(b-q[1]))<0)q[len++] = q[1];
			if(sgn((a-q[2])*(b-q[2]))<0)q[len++] = q[2];
		}
		q[len++] = b;
		if(len == 4 && sgn((q[0]-q[1])*(q[2]-q[1]))>0)swap(q[1],q[2]);
		double res = 0;
		for(int i = 0;i < len-1;i++){
			if(relation(q[i])==0||relation(q[i+1])==0){
				double arg = p.rad(q[i],q[i+1]);
				res += r*r*arg/2.0;
			}
			else{
				res += fabs((q[i]-p)^(q[i+1]-p))/2.0;
			}
		}
		return res;
	}
};

Point a,b;
circle c;
Line l;
int main() 
{
	a.input();
	b.input();
	c.input();
	l=Line(a,b);
	if(c.relationseg(l)!=2)
	{
		printf("%.6lf\n",l.length());
	}
	else 
	{
		double A=acos(c.r/a.distance(c.p));
		double B=acos(c.r/b.distance(c.p));		
		double sum=c.p.rad(a,b);
		double C=sum-A-B;
		double ans=0;
		double la,lb;
		la=a.distance(c.p);
		lb=b.distance(c.p);
		ans+=la*sin(A);
		ans+=lb*sin(B) ;
		ans+=c.r*C;
		printf("%.6lf\n",ans);
	}
}

B 组队  

排序,枚举队伍最小值然后二分求出该情况下的队伍人数,即可

#include
using namespace std;
int T;
int n,m;
int a[200005];
int main()
{
    scanf("%d",&T)  ;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i

C 十面埋伏

DFS暴力即可

#include 
#define pai pair 
using namespace std;
int n,m;
char a[505][505];
int b[505][505];
int main()
{
	scanf("%d%d",&n,&m);
	memset(a,'.',sizeof(a));
	for(int i=1;i<=n;i++)
	{
		scanf("%s",a[i]+1);
	}
	queue p;
	p.push(pai(0,0));
	while(p.size())//BFS 对外围'.' 染色 
	{
		
		pai P=p.front();
		p.pop();
		int i=P.first;
		int j=P.second;
		int aa[4]={-1,0,1,0};
		int bb[4]={0,-1,0,1};
		for(int k=0;k<4;k++)
		{
			int ii=i+aa[k];
			int jj=j+bb[k];
			if(ii>=0&&jj>=0&&ii<=n&&jj<=m&&a[ii][jj]=='.'&&b[ii][jj]==0)
			{
				b[ii][jj]=1;
				p.push(pai(ii,jj));
			}
		}
	}
	
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]=='#')//暴力改成 '*' 
			{
				if(a[i-1][j]=='.') a[i-1][j]='*';
				if(a[i][j-1]=='.') a[i][j-1]='*';
				if(a[i+1][j]=='.') a[i+1][j]='*';
				if(a[i][j+1]=='.') a[i][j+1]='*';
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]=='*')
			{				
			 if(b[i][j])a[i][j]='*';
			 else a[i][j]='.'; //敌人内部不需要士兵 
			}
			
		}
	}
	for(int i=1;i<=n;i++)
	{
		printf("%s\n",a[i]+1);
	}
}

D 牛妹吃豆子

二维差分例题

#include
#define ll long long
using namespace std;
int n,m,k,q;
ll a[2003][2003];
int main()
{
	scanf("%d%d%d%d",&n,&m,&k,&q);
	for(int i=0;i

E 旅旅旅游

3次最短路
1.数组D[i] 求1起点到 i 的最短路

2.数组d[i] 求n 起点到 i 的最短路

枚举每条边 u v c

若满足 d[u]+D[v]+c==D[n]||d[v]+D[u]+c==D[n] 则在最短路径上,忽略

若不满足 加入GG边集,重新建图

3. 再次 ,数组D[i] 求1起点到 i 的最短路

枚举每个城市,若D[i] ==inf 说明不存在路径可达 非法 输出NO

#include
#define pai pair 
#define ll long long
using namespace std;

int n,m;
vector G[100005],g[100005];
struct node
{
	int u,v,c;
}N[500005];
ll D[100005],d[100005];
void dij1()
{
	priority_queue,greater > q;
	D[1]=0;
	q.push(pai(0,1));
	while(q.size())
	{		
		pai P=q.top();
		q.pop();
		int F=P.first,S=P.second;
		if(F>D[S]) continue;
		for(auto T:G[S])
		{		 
			if(T.first+D[S],greater > q;
	d[n]=0;
	q.push(pai(0,n));
	while(q.size())
	{		
		pai P=q.top();
		q.pop();
		int F=P.first,S=P.second;
		if(F>d[S]) continue;
		for(auto T:G[S])
		{		 
			if(T.first+d[S],greater > q;
	D[1]=0;
	q.push(pai(0,1));
	while(q.size())
	{		
		pai P=q.top();
		q.pop();
		int F=P.first,S=P.second;
		if(F>D[S]) continue;
		for(auto T:g[S])
		{		 
			if(T.first+D[S]

F 斗兽棋

每个动物编号 

if(牛妹赢 ) puts("tiangou txdy");

else puts("tiangou yiwusuoyou");

#include
using namespace std;
char s[20],ss[20];
int main()
{
	map mp;
	mp['e']=0;
	mp['t']=1;
	mp['c']=2;
	mp['m']=3;
	scanf("%s %s",s,ss);
	int a=mp[s[0]];
	int b=mp[ss[0]];
	if((b+1)%4==a) puts("tiangou txdy");
	else puts("tiangou yiwusuoyou");
	
}

G 做题

排序,贪心  注意long long 

#include
#define ll long long 
using namespace std;
ll n;
long long m;
ll a[500005];
int main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=0;i

H 人人都是好朋友

每个下手用map 取1~num 编号 ,离散化

并查集 即可

#include
using namespace std;
int f[2000006],dep[1000006];
struct node
{
	int a,b,c;
}N[1000006];

int find(int x)
{
	if(f[x]==x) return x;
	else f[x]=find(f[x]);
}
void uin(int x,int y)
{	
	int fx=find(x);
	int fy=find(y);
	if(fx==fy) return ;
	if(dep[fx] fa;
		int num=1;
		for(int i=0;i

I 求和

求每个节点dfs序 保存每个节点子树的dfs序范围 L[i],R[i]

建立线段树,即可

自省:

up(1,1,n,L[a],x)   !!!

NO  up(1,1,4000006,L[a],x)  

 

#include
#define ll long long
#define ls o*2
#define rs o*2+1 
#define mid (l+r)/2
using namespace std;
int n,m,k;
ll tree[8000006];
vector G[1000006];
ll v[1000006];
int L[1000006];
int R[1000006];
int cnt=0;
void  dfs(int a,int fa)
{
	L[a]=++cnt;
	for(auto P:G[a])
	{
		if(P==fa) continue;
		dfs(P,a);
	}
	R[a]=cnt;
}
void  up(int o,int l,int r,int p,ll v)
{
	if(l==r)
	{
		tree[o]+=v;
		return ;
	}
		
	if(p<=mid) up(ls,l,mid,p,v);
	else up(rs,mid+1,r,p,v);
	tree[o]=tree[ls]+tree[rs];
}

ll qu(int o,int l,int r,int ql,int qr)
{
	if(ql<=l&&r<=qr)
	{
		return tree[o];
	}
	ll sum=0;
	if(ql<=mid) sum+=qu(ls,l,mid,ql,qr);
	if(mid+1<=qr) sum+=qu(rs,mid+1,r,ql,qr);
	return sum;
}
int main()
{
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&v[i]);
	}
	for(int i=0;i

J 建设道路

(a_{i}-a_{j})^{2}=a_{i}^{2}+ a_{j}^{2}-2a_{i}a_{j}

每个城市ai的度为n-1  则a_{i}^{2}}会计算n-1次

a_{i}a_{j} 可利用前缀和求

两部分相加即可

关于取模 :务必饱和时取模!吝啬你就wa了(一顿乱%)

#include
#define ll long long 
#define mod 1000000007
using namespace std;
int n;
ll a[500005];
int main()
{
	scanf("%d",&n);
	ll ans=0;
	for(int i=0;i

 

 

你可能感兴趣的:(牛客小白月赛24题解 A-J)