Loading web-font TeX/Math/Italic

CF中计算几何*2500+的好题精选

提前开个坑,健忘的我这种题做过了肯定马上又不会了,于是把他们写下来

  1. CF70D Professor's task

动态维护一个凸包,把其分成上下两个凸壳

加点时如果不在上凸壳内部,更新上凸壳

加点时如果不在下凸壳内部,更新下凸壳

更新用 STLmap ,二分找 x 坐标小于等于当前加入点的 x 坐标最大的点,取其为向左删点的起始点

这个点的下一个点即为向右删点的起始点

循环删点,直到判叉积时发现不符合了

Code:

#include<bits/stdc++.h>
#define ll long long
#define PII pair<ll,ll>
#define mp make_pair
#define fi first
#define se second
using namespace std;
map<ll,ll> top,bot;
PII xl(PII x,PII y){return mp(y.fi-x.fi,y.se-x.se);}
ll cross(PII a,PII b){return a.fi*b.se-a.se*b.fi;}
bool isd_top(ll x,ll y){
	auto it=top.lower_bound(x);
	if(it==top.end()) return 0;
	if(it->fi==x) return y<=it->se;
	if(it==top.begin()) return 0;
	auto i=it,j=it; j--;
	return cross(xl(*j,*i),xl(*j,mp(x,y)))<=0;
}
bool isd_bot(ll x,ll y){
	auto it=bot.lower_bound(x);
	if(it==bot.end()) return 0;
	if(it->fi==x) return y>=it->se;
	if(it==bot.begin()) return 0;
	auto i=it,j=it; j--;
	return cross(xl(*j,*i),xl(*j,mp(x,y)))>=0;
}
bool del_top(map<ll,ll>::iterator i){
	if(i==top.begin()) return 0;
	auto j=i,k=i; --j,++k;
	if(k==top.end()) return 0;
	if(cross(xl(*j,*i),xl(*j,*k))>=0){
		top.erase(i); return 1;
	}	return 0;
}
bool del_bot(map<ll,ll>::iterator i){
	if(i==bot.begin()) return 0;
	auto j=i,k=i; --j,++k;
	if(k==bot.end()) return 0;
	if(cross(xl(*j,*i),xl(*j,*k))<=0){
		bot.erase(i); return 1;
	}
	return 0;
}
void ins_up(ll x,ll y){
	if(isd_top(x,y)) return;
	top[x]=y;
	auto i=top.find(x),j=i;
	if(i!=top.begin()){j--; while(del_top(j++)) j--;}
	if(++j!=top.end()) while(del_top(j--)) j++;
	return;
}
void ins_down(ll x,ll y){
	if(isd_bot(x,y)) return;
	bot[x]=y;
	auto i=bot.find(x),j=i;
	if(i!=bot.begin()){j--; while(del_bot(j++)) j--;}
	if(++j!=bot.end()) while(del_bot(j--)) j++;
	return;
}
int main(){
	ll q,op,x,y;
	scanf("%lld",&q);
	while(q--){
		scanf("%lld%lld%lld",&op,&x,&y);
		if(op==1) ins_up(x,y),ins_down(x,y);
		else if(isd_top(x,y) && isd_bot(x,y))
			puts("YES"); else puts("NO");
	}	return 0;
}
  1. Eligible Segments

问有几条以其中两个顶点为端点的线段,能被以其余点为圆心,半径为 R 的圆都覆盖到

可以枚举起始点(这里设他为 i),再枚举终止点 j ,作点 i 到以点 j 为圆心的圆的两条切线,记下他们的角度范围(不知道能不能这么说?),最后求交集即可

sqrt 的地方 1e5 乘起来会炸 int ,不开 long longTLE

Code:

#include<bits/stdc++.h>
#define db long double
#define ll long long 
using namespace std;
const ll M=3e3+7;
const db PI=3.14159265,eps=1e-9;
ll n,R,x[M],y[M],ans; bool stl[M][M],sdht[M];
inline db dis(ll i,ll j){
	return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
inline db calc_m(ll i,ll j){
	if(x[i]==x[j]) return y[j]>y[i]?PI/2:(PI/2+PI);
	if(y[i]==y[j]) return x[j]>x[i]?0:PI;
	db now=atan2(abs(y[j]-y[i]),abs(x[j]-x[i]));
	if(x[i]<x[j] && y[i]<y[j]) return now;
	if(x[i]>x[j] && y[i]<y[j]) return PI-now;
	if(x[i]>x[j] && y[i]>y[j]) return PI+now;
	if(x[i]<x[j] && y[i]>y[j]) return 2*PI-now;
	//这些都好烦啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
	return 114514.1919810;
}
struct Int{
	db l,r;
	Int(db _l,db _r){l=_l,r=_r;} Int(){}
	Int Mov_r(db del){return Int(l+del,r+del);}
	inline bool In(db x){return l-eps<=x&&x<=r+eps;}
};
inline Int intersection(Int x, Int y){
	return Int(max(x.l,y.l),min(x.r,y.r));
}
int main(){
	scanf("%lld%lld",&n,&R);
	for(int i=1;i<=n;i++) scanf("%lld%lld",&x[i],&y[i]),sdht[i]=1;
	for(int i=1;i<=n;i++){
		Int Itsct(0,2*PI); bool bz_x_z=0;
		for(int j=1;j<=n && Itsct.l-eps<Itsct.r;j++){
			db d=dis(i,j); if(d<=R) continue;
			db nj=calc_m(i,j),dt=asin(R/d);
			Int cur(nj-dt-eps,nj+dt+eps);
			if(cur.r>2*PI) cur=cur.Mov_r(-2*PI);
			Int nw=intersection(Itsct,cur);
			if(cur.l<0) if(bz_x_z) Itsct=nw; else{
					if(Itsct.l==0 && Itsct.r==2*PI) Itsct=cur;
					else if(nw.l-eps<nw.r) Itsct=nw;
					else Itsct=intersection(Itsct.Mov_r(-2*PI),cur);
					bz_x_z=1;
				}
			else if(bz_x_z){
				if(nw.l-eps<nw.r) Itsct=nw;
				else Itsct=intersection(Itsct,cur.Mov_r(-2*PI));
			}else Itsct=nw;
		}
		if(Itsct.l-eps>Itsct.r) memcpy(stl[i],sdht,sizeof(sdht));
		else for(int j=1;j<=n;j++){
			if(i==j) continue; db nj=calc_m(i,j);
			stl[i][j]|=!(Itsct.In(nj)||(Itsct.Mov_r(2*PI)).In(nj));
		}
	}
	for(int i=1;i<=n;i++){
		ans+=n-i;
		for(int j=i+1;j<=n;j++) ans-=(stl[i][j]|stl[j][i]);
	}
	printf("%lld",ans);
	return 0;
}
  1. Spectator Riots

woc,又觅到一道凸包题((

极简题意: 给你一堆点,让你用一个圆包住凸包

一些限制:

  • 圆要最大

  • 圆要与凸包上至少 3 个点相交

如何求这个圆?

首先易知,必然取三个相邻的凸包上的点

然后好像不需要然后,O(n) 枚举哪三个点即可?

水题 get !

(然后我没看到点有界于是光荣 Wa on 2

做完这道题以后感觉最难的是建点...

Code:

#include<bits/stdc++.h>
#define ll long long
#define lll __int128
#define db double
using namespace std;
const ll M=1e6+7; 
ll n,nn,nx,ny,nv,a1,a2,a3; db now,ans;
struct node{db x,y;}p[M],tb[M];
db check(node a1,node a2,node b1,node b2){
	return (a2.x-a1.x)*(b2.y-b1.y)-(b2.x-b1.x)*(a2.y-a1.y); 
	//<0表右转 =0表共线 >0表左转 
}
db dis(node p1,node p2){
	return sqrt((lll)(p2.y-p1.y)*(p2.y-p1.y)+(lll)(p2.x-p1.x)*(p2.x-p1.x));
}
bool cmp(node p1,node p2){
	db tmp=check(p[1],p1,p[1],p2);
	if(tmp>0 ||(tmp==0 && dis(p[1],p1)<dis(p[1],p2))) return 1;
	return 0;
}
db ddis(node x){return sqrt(x.x*x.x+x.y*x.y);}
db work(ll a1,ll a2,ll a3){
	node a=node{tb[a2].x-tb[a1].x,tb[a2].y-tb[a1].y};
	node b=node{tb[a3].x-tb[a1].x,tb[a3].y-tb[a1].y};
	node c=node{tb[a3].x-tb[a2].x,tb[a3].y-tb[a2].y};
	return ddis(a)*ddis(b)*ddis(c)/fabs(b.x*c.y-b.y*c.x);
}
int main(){
	scanf("%lld",&nn);
	for(int i=1;i<=nn;i++){
		scanf("%lld%lld%lld",&nx,&ny,&nv);
		p[++n].x=nx,p[n].y=ny+nv;
		if(p[n].y>1e5){
			p[n].x+=p[n].y-1e5,p[n].y=1e5;
			p[n].x=min(1e5,p[n].x);//↘
		}
		if(n!=1&&(p[n].y<p[1].y ||(p[n].y==p[1].y && p[n].x<p[1].x)))
			swap(p[1],p[n]);
		p[++n].x=nx,p[n].y=ny+nv;
		if(p[n].y>1e5){
			p[n].x-=p[n].y-1e5,p[n].y=1e5;
			p[n].x=max(0.0,p[n].x);//↙
		}
		if(n!=1&&(p[n].y<p[1].y ||(p[n].y==p[1].y && p[n].x<p[1].x)))
			swap(p[1],p[n]);
		p[++n].x=nx,p[n].y=ny-nv;
		if(p[n].y<0){
			p[n].x-=p[n].y,p[n].y=0;
			p[n].x=min(1e5,p[n].x);//↗
		}
		if(p[n].y<p[1].y ||(p[n].y==p[1].y && p[n].x<p[1].x)) swap(p[1],p[n]);
		p[++n].x=nx,p[n].y=ny-nv;
		if(p[n].y<0){
			p[n].x+=p[n].y,p[n].y=0;
			p[n].x=max(0.0,p[n].x);//↖
		}
		if(p[n].y<p[1].y ||(p[n].y==p[1].y && p[n].x<p[1].x)) swap(p[1],p[n]);
		p[++n].x=nx+nv,p[n].y=ny;
		if(p[n].x>1e5){
			p[n].y-=p[n].x-1e5,p[n].x=1e5;
			p[n].y=max(0.0,p[n].y);//↙
		}
		if(p[n].y<p[1].y ||(p[n].y==p[1].y && p[n].x<p[1].x)) swap(p[1],p[n]);
		p[++n].x=nx+nv,p[n].y=ny;
		if(p[n].x>1e5){
			p[n].y+=p[n].x-1e5,p[n].x=1e5;
			p[n].y=min(1e5,p[n].y);//↖
		}
		if(p[n].y<p[1].y ||(p[n].y==p[1].y && p[n].x<p[1].x)) swap(p[1],p[n]);
		p[++n].x=nx-nv,p[n].y=ny;
		if(p[n].x<0){
			p[n].y-=p[n].x,p[n].x=0;
			p[n].y=min(p[n].y,1e5);//↗
		}
		if(p[n].y<p[1].y ||(p[n].y==p[1].y && p[n].x<p[1].x)) swap(p[1],p[n]);
		p[++n].x=nx-nv,p[n].y=ny;
		if(p[n].x<0){
			p[n].y+=p[n].x,p[n].x=0;
			p[n].y=max(p[n].y,0.0);//↘
		}
		if(p[n].y<p[1].y ||(p[n].y==p[1].y && p[n].x<p[1].x)) swap(p[1],p[n]);
	}
	sort(p+2,p+1+n,cmp),tb[1]=p[1];
	int cnt=1;
	for(int i=2;i<=n;i++){
		while(cnt>1&&check(tb[cnt-1],tb[cnt],tb[cnt],p[i])<=0) cnt--;
		tb[++cnt]=p[i];
	}
	for(int i=1;i<=cnt-2;i++){now=work(i,i+1,i+2); if(now>ans) ans=now,a1=i,a2=i+1,a3=i+2;}
	now=work(cnt,1,2); if(now>ans) ans=now,a1=cnt,a2=1,a3=2;
	now=work(cnt-1,cnt,1); if(now>ans) ans=now,a1=cnt-1,a2=cnt,a3=1;
	printf("%.lf %.lf\n%.lf %.lf\n%.lf %.lf",tb[a1].x,tb[a1].y,tb[a2].x,tb[a2].y,tb[a3].x,tb[a3].y);
	return 0;
}
  1. Symmetric Projections

题意(谷内翻译):

给出 n 个点 (x,y) ,对于一条过原点的直线,如果 n 个点在它上面的投影是中心对称的即存在一个点使得投影旋转 180 度后能和旋转前重合,这个点不一定是原点,那么称这是一条好的直线.

给出所有的点,问有多少条好的直线,如果有无限条好的直线,输出 -1.

还是看 CF 官网上的图吧,洛谷的翻译我是没看懂(wtcl

给出的点为 (1,2),(2,1),(3,3),符合条件的直线有红,蓝,绿三条

前置知识

  1. 假设有 n 个点,坐标分别是(x1,y1)(x2,y2)...(xn,yn)
    则其重心的坐标是

x=(x1+x2+...+xn)/ny=(y1+y2+...+yn)/n

  1. 如果一条直线满足条件,那这 n 个点的在这条直线投影点一定是关于重心的投影点对称的

证明:去问 djwj233

Step 1

删掉无用的点

求出重心后,易知每对关于重心对称的点对,都是可以删掉的

  • 在这里判有无数解的情况,即删掉一些点以后,点没了

O(n2)

Step 2

分类讨论

  • 剩下奇数个点

必然有一个点与重心的连线垂直于满足条件的直线,暴力枚举点,并枚举剩下的点的投影,判是否对称

这个比较简单,易知所有垂线的斜率相同,于是只要把当前枚举着的点和重心的连线的斜率求出来,用 k 去推 b , 用相似三角形易证,如果这些 x 坐标为 0y 坐标为 bi 的一堆点构成了中心对称图形,则每个点的投影点所构成的图形也必然是中心对称图形

O(n2 log n)

  • 剩下偶数个点

选一个点,必然会有另一个点的投影来与他的投影对称,枚举之

这里有一个结论,就是说因为三条垂线互相平行且间距一样所以从重心引的垂线必然经过第一个点和枚举点的连线的中点,于是 k 也变得很好求了,证明的话用全等三角形

O(n2 log n)

Step 3

统计答案

就是每次枚举点能使所有点的投影点集形成中心对称图形,答案加 1

Extra 1

特判 a=(x,y)x=0 的情况,不然除以 0 会死透

Extra 2

枚举点之后算出的斜率如果不判重会 Wa

我是把 a=(x,y) 变成 a=(x/gcdx,y,y/gcdx,y)

堆成 pair 放进 map

Extra 2-1

y=0gcdx,y 怎么办?

再特判(我除了特判啥也不会 /kk

Extra 3

实数判相等

算了做这题的人肯定都会,a==b => fabs(a-b)<=eps

Extra 4

精度问题,我不开 long double 挂了

好像就这些(

Code:

#include<bits/stdc++.h>
#define ll long long
#define db long double
#define eps 1e-7
using namespace std;
const int M=2e3+7;
map<pair<ll,ll>,bool> ma;
ll n,nown,x[M],y[M],cntx,cnty,cntb,ans,gcdsum;
bool del[M],used,used_;
db b[M];
bool check(int cntb){
	for(int i=1;i+i<=cntb;i++)
		if(fabs(b[i]+b[cntb-i+1]-b[0]-b[0])>=eps)
			return 0;
	return 1;
}
ll Gcd(ll a,ll b){
	if(b==0) return a;
	return Gcd(b,a%b);
}
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld%lld",&x[i],&y[i]);
		cntx+=x[i],cnty+=y[i],x[i]*=n,y[i]*=n;
		//珍爱生命,远离double,这样写可以在这里避免产生小数
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(x[i]+x[j]==cntx+cntx && y[i]+y[j]==cnty+cnty)
				del[i]=1,del[j]=1;
	for(int i=1;i<=n;i++)
		if(!del[i]){
			nown++;
			x[nown]=x[i],y[nown]=y[i];
		}
	if(!nown) return puts("-1"),0;
	n=nown;
	if(n%2==0){
		//枚举和第一个点的投影对称的投影点
		for(int i=2;i<=n;i++){
			db midx,midy;
			midx=(x[1]+x[i])*0.5;
			midy=(y[1]+y[i])*0.5;
			if(midx-cntx==0){
				if(used) goto js1;
				used=1;
				//特判掉,不然会寄
				for(int j=1;j<=n;j++)
					b[j]=x[j];
				b[0]=(b[1]+b[i])*0.5;
			}else{
				gcdsum=Gcd(midy-cnty,midx-cntx);
				db k=(db)(midy-cnty)/(midx-cntx);
				if(midy-cnty==0 && used_) goto js1;
				if(midy-cnty!=0 && ma[make_pair((midy-cnty)/gcdsum,(midx-cntx)/gcdsum)])
					goto js1;
				if(midy-cnty==0) used_=1;
				else ma[make_pair((midy-cnty)/gcdsum,(midx-cntx)/gcdsum)]=1;
				for(int j=1;j<=n;j++)
					b[j]=y[j]-k*x[j];
				b[0]=midy-k*midx;
			}
			sort(b+1,b+1+n);
			if(check(n)) ans++;
			js1:;
		} 
	}else{
		for(int i=1;i<=n;i++){
			cntb=0;
			if(x[i]-cntx==0){
				//特判掉,不然也会寄
				if(used) goto js2;
				used=1;
				for(int j=1;j<=n;j++)
				 	if(j!=i) b[++cntb]=x[j];
				b[0]=x[i];
			}else{
				gcdsum=Gcd(y[i]-cnty,x[i]-cntx);
				db k=(db)(y[i]-cnty)/(x[i]-cntx);
				//y=kx+b,b=y-kx
				if(y[i]-cnty==0 && used_) goto js2;
				if(y[i]-cnty!=0 && ma[make_pair((y[i]-cnty)/gcdsum,(x[i]-cntx)/gcdsum)])
					goto js2;
				if(y[i]-cnty==0) used_=1;
				else ma[make_pair((y[i]-cnty)/gcdsum,(x[i]-cntx)/gcdsum)]=1;
				for(int j=1;j<=n;j++)
					if(j!=i) b[++cntb]=y[j]-k*x[j];
				b[0]=y[i]-k*x[i];
			}
			sort(b+1,b+1+cntb);
			if(check(cntb)) ans++;
			js2:;
		}
	}
	printf("%lld",ans);
	return 0;
}
  1. Swap Pass

很有趣的一道题

先用极角排序,并查集维护两个点是否在同一个需求环上

第一次把每个点自己当前数和需要数并在一起,于是我们有了一堆环

第二次我们尝试把多个环并成一个,把极角排序后相邻的,不在同一环上的并在一起,模拟交换数值,答案统计

于是我们要输出答案,易证此时第一个点与任何点连边都不会相交,每次用他去与其他点交换数值,统计答案即可

Code:

#include<bits/stdc++.h>
#define db double
using namespace std;
const int M=2007;
int n,nown,fa[M],nowx,nowy,nowp,need[M],pos[M];
struct node{int x,y,a,id; db jj;}p[M];
vector<pair<int,int> > ans;
int find(int x){
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);
}
bool cmp(node x,node y){
	return x.jj<y.jj;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].a);
		p[i].id=i;
		if(p[i].a!=i) p[++nown]=p[i];
	}
	for(int i=1;i<=n;i++) fa[i]=i;
	n=nown;
	if(!n) return putchar('0'),0;
	nowx=p[1].x,nowy=p[1].y,nowp=1;
	for(int i=2;i<=n;i++)
		if(p[i].x<nowx ||(p[i].x==nowx && p[i].y<nowy))
			nowx=p[i].x,nowy=p[i].y,nowp=i;
	swap(p[1],p[nowp]);
	for(int i=2;i<=n;i++)
		p[i].jj=atan2(p[i].y-nowy,p[i].x-nowx);
	sort(p+2,p+1+n,cmp);
	for(int i=1;i<=n;i++)
		fa[find(p[i].id)]=find(p[i].a);
	for(int i=2;i<n;i++){
		int f1=find(p[i].id),f2=find(p[i+1].id);
		if(f1!=f2){
			ans.push_back(make_pair(p[i].id,p[i+1].id));
			swap(p[i].a,p[i+1].a),fa[f1]=f2;
		}
	}
	for(int i=1;i<=n;i++) pos[p[i].id]=i;
	while(p[1].a!=p[1].id){
		int u=pos[p[1].a];
		ans.push_back(make_pair(p[1].id,p[u].id));
		swap(p[1].a,p[u].a);
	}
	for(int i=1;i<=n;i++)
		if(p[i].a!=p[i].id) return puts("-1");
	printf("%d",ans.size());
	for(auto i:ans) printf("\n%d %d",i.first,i.second);
	return 0;
}
  1. Ruminations on Ruminants

前置知识:西姆松定理

注意精度,另外应该看下代码都能看懂

Code:

#include<bits/stdc++.h>
#define db long double
#define eps 1e-11
using namespace std;
const int M=2021;
int n,a,b,c,kp,now,ans,lp,kk;
db x[M],y[M],k[M];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&a,&b,&c);
		//ax+by=c
		//by=c-ax
		//y=(c-ax)/b
		//y=-a/bx+c/b
		//k_real=b/a
		//y=b/a*x
		//y=-a/bx+c/b
		//(b/a)x=(-a/b)x+c/b
		//(b/a+a/b)x=c/b
		//(b*b+a*a)x=c*a
		x[i]=(db)c*a/((db)b*b+a*a);
		y[i]=(db)c*b/((db)b*b+a*a);
	}
	for(int i=1;i<=n-2;i++){
		kk=kp=0,lp=now=1;
		for(int j=i+1;j<=n;j++){
			if(fabs(x[j]-x[i])<eps)
				if(fabs(y[j]-y[i])<eps) kk++;
				else k[++kp]=-114514.1919810;
			else k[++kp]=(y[j]-y[i])/(x[j]-x[i]);
		}
		for(int j=1;j<=kk;j++) ans+=n-i-j;
		sort(k+1,k+1+kp);
		for(int j=1;j<=kp;j++){
			while(fabs(k[j]-k[lp])>eps) lp++;
			ans+=j-lp;
		}
	}
	printf("%d",ans);
	return 0;
}
  1. Triangles 3000

其实这题我没脸放上来 [捂脸]

但是为了凑数我还是放上来了

正解是什么我不会,于是我打了个暴力艹了过去

放下代码吧

Code:

#pragma GCC optimize("Ofast,no-stack-protector")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<bits/stdc++.h>
#define db double
using namespace std;
inline db calc(db a,db b,db c,db d,db e,db f,db g,db h,db i){
    double z=(a*(e*i-f*h)-b*(d*i-f*g)-c*(e*g-d*h));
    return abs(z*z/(2*(a*e-b*d)*(a*h-b*g)*(d*h-e*g)));
}
db A[3007],B[3007],C[3007];
int main(){
    int n;
    scanf("%d",&n); 
    for(int i=1;i<=n;i++)
		scanf("%lf%lf%lf",&A[i],&B[i],&C[i]);
    double s=0;
    for(int i=1;i<n-1;i++) for(int j=i+1;j<n;j++) for(int k=j+1;k<=n;k++)
        s+=calc(A[i],B[i],C[i],A[j],B[j],C[j],A[k],B[k],C[k]);
    return printf("%.10lf",s/(1ll*n*(n-1)*(n-2)/6)),0;
}
posted @   俞开  阅读(88)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示