2019 牛客多校五 D generator 3

这也是一道不难想但不好写的题。。。
求平面上点围城的凸包的面积,点的横、纵坐标分别由一个模线性随机数生成器生成。凸包点数<=1e18, 取模的范围<=2e5。

显然横、纵坐标不超过2e5次生成就会出现循环,所以只用先分别求出第一个循环节。然后如果几个点在一条竖直线上,则只会取y坐标最大或最小的两个点。所以在只需要对每一个x的位置查询往后跳不超过n步,每一次跳跃x循环节长度后y上的最大值和最小值。只需使用st表维护即可。

中间被卡了很长时间,因为要处理循环节产生之前的部分,这个过程注意不能把范围超过n。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. typedef long long ll;
  5.  
  6. const int N=200010;
  7. int visx[N],visy[N];
  8. ll sx[N],sy[N],sxc,syc;
  9.  
  10. int stma[N][64],stmi[N][64],xmi[N],xma[N];
  11.  
  12. vector<int> qux[N];
  13.  
  14. ll area(ll stx,ll sty,ll x2, ll y2, ll x3, ll y3){
  15. 	return (x2-stx)*(y3-sty)-(x3-stx)*(y2-sty);
  16. }
  17.  
  18. ll stx[N],sty[N],stm;
  19.  
  20. int main(){
  21. 	ll x0,y0,x00,y00,ax,ay,bx,by,px,py,n;
  22. 	cin>>x00>>y00>>ax>>ay>>bx>>by>>px>>py>>n;
  23. 	memset(xmi,0x3f,sizeof xmi);
  24. 	memset(xma,-1,sizeof xma);
  25. 	x0=x00; y0=y00;
  26. 	memset(visx,-1,sizeof visx);
  27. 	memset(visy,-1,sizeof visy);
  28. 	while (visx[x0]==-1){
  29. 		visx[x0]=sxc;
  30. 		sx[sxc++]=x0;
  31. 		x0=(x0*ax+bx)%px;
  32. 	}
  33. 	while (visy[y0]==-1){
  34. 		visy[y0]=syc;
  35. 		sy[syc++]=y0;
  36. 		y0=(y0*ay+by)%py;
  37. 	}
  38. 	if (visy[y0]>visx[x0]){
  39. 		x0=y00; y0=x00;
  40. 		swap(ax,ay); swap(bx,by); swap(px,py);
  41. 		memset(visx,-1,sizeof visx);
  42. 		memset(visy,-1,sizeof visy);
  43. 		sxc=syc=0;
  44. 		while (visx[x0]==-1){
  45. 			visx[x0]=sxc;
  46. 			sx[sxc++]=x0;
  47. 			x0=(x0*ax+bx)%px;
  48. 		}
  49. 		while (visy[y0]==-1){
  50. 			visy[y0]=syc;
  51. 			sy[syc++]=y0;
  52. 			y0=(y0*ay+by)%py;
  53. 		}
  54. 	}
  55. 	int tdy=syc,sy0=visy[y0];
  56. 	while (tdy<sxc) sy[tdy++]=y0, y0=(y0*ay+by)%py;
  57. 	int stt=visx[x0]-sy0;
  58. 	for (int i=0;i<n && i<visx[x0];i++){
  59. 		xmi[sx[i]]=min(xmi[sx[i]],(int)sy[i]);
  60. 		xma[sx[i]]=max(xma[sx[i]],(int)sy[i]);
  61. 	}
  62. 	n-=visx[x0];
  63. 	rotate(sx,sx+visx[x0],sx+sxc);
  64. 	rotate(sy,sy+sy0,sy+syc);
  65. 	syc-=sy0; sxc-=visx[x0];
  66. 	rotate(sy,sy+stt%syc,sy+syc);
  67. 	for (int i=0;i<sxc && i<n;i++) qux[sx[i]].push_back(i);
  68. 	for (int i=0;i<syc;i++)
  69. 		stma[i][0]=stmi[i][0]=sy[i];
  70. 	int dk=log(n/sxc)/log(2)+1;
  71. 	for (int k=1;k<=dk;k++)
  72. 		for (ll i=0;i<syc;i++)
  73. 			stma[i][k]=max(stma[i][k-1],stma[(i+(1ll<<(k-1))%syc*sxc)%syc][k-1]),
  74. 			stmi[i][k]=min(stmi[i][k-1],stmi[(i+(1ll<<(k-1))%syc*sxc)%syc][k-1]);
  75. 	for (int i=0;i<px;i++)
  76. 		for (auto xp:qux[i]){
  77. 			if (n<1) continue;
  78. 			ll l=xp%syc,sc=n/sxc+(xp<n%sxc);
  79. 			if (sc==0) continue;
  80. 			int p=log(sc)/log(2.0); 
  81. 			ll r=(xp+(sc-(1ll<<p))%syc*sxc)%syc;
  82. 			xmi[i]=min(xmi[i],min(stmi[l][p],stmi[r][p]));
  83. 			xma[i]=max(xma[i],max(stma[l][p],stma[r][p]));
  84. 		}
  85.  
  86. 	for (int i=0;i<px;i++) if (xmi[i]<1e6){
  87. 		while (stm>1 && area(stx[stm-2],sty[stm-2],stx[stm-1],sty[stm-1],i,xmi[i])<=0) stm--;
  88. 		stx[stm]=i; sty[stm++]=xmi[i];
  89. 	}
  90. 	int tstm=stm;
  91. 	for (int i=px-1;i>=0;i--) if (xma[i]>-1){
  92. 		while (stm>tstm && area(stx[stm-2],sty[stm-2],stx[stm-1],sty[stm-1],i,xma[i])<=0) stm--;
  93. 		stx[stm]=i; sty[stm++]=xma[i];
  94. 	}
  95. 	ll ans=0;
  96. 	for (int i=2;i<stm;i++)
  97. 		ans+=area(stx[0],sty[0],stx[i-1],sty[i-1],stx[i],sty[i]);
  98. 	cout<<ans<<'\n';
  99. 	return 0;
  100. }

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注