[关闭]
@y20070316 2017-02-17T00:59:36.000000Z 字数 7813 阅读 1043

GDKOI2017模拟赛三

OI 校内赛


【xsy1084】Evaluation - 莫比乌斯变换 or 快速沃尔什变换

题意

给定
,其中

分析1:莫比乌斯变换

假如存在某个变换,使得。我们快速的进行变换和逆变换,则可以快速求解答案。

这里介绍莫比乌斯变换:


则有:

考虑如何进行变换和逆变换。

变换:给定,求
考虑dp,设表示对于集合,前位可以任意改动的所有子集的和。
奠基:


转移:


答案:

我们还可以考虑降维,写成一段很精简的代码。

  1. void Trans(int *f,int n) {
  2. for (int i=1;i<(1<<n);i<<=1)
  3. for (int j=0;j<(1<<n);j++)
  4. if (j&i)
  5. f[j]+=f[j^i];
  6. }

逆变换:给定,求
怎么变换过去的,就怎么变换回来。
直接和上面的代码相反就好了。

代码1:莫比乌斯变换

  1. #include <cstdio>
  2. #include <cctype>
  3. #define F(i,a,b) for (int i=(a);i<=(b);i++)
  4. #define LL unsigned int
  5. LL rd(void);
  6. const int N=1048576;
  7. int n,nk;
  8. LL f[N];
  9. LL g[N];
  10. LL h[N];
  11. LL ans;
  12. int main(void) {
  13. #ifndef ONLINE_JUDGE
  14. freopen("a.in","r",stdin);
  15. freopen("a.out","w",stdout);
  16. #endif
  17. n=rd();
  18. nk=(1<<n);
  19. F(i,0,nk-1)
  20. f[i]=rd();
  21. F(i,0,nk-1)
  22. g[i]=rd();
  23. for (int j=1;j<nk;j<<=1)
  24. F(i,0,nk-1) if (i&j) {
  25. f[i]+=f[i^j];
  26. g[i]+=g[i^j];
  27. }
  28. F(i,0,nk-1)
  29. h[i]=f[i]*g[i];
  30. for (int j=1;j<nk;j<<=1)
  31. F(i,0,nk-1) if (i&j)
  32. h[i]-=h[i^j];
  33. F(i,0,nk-1)
  34. ans+=h[i]*(i+1);
  35. printf("%u\n",ans);
  36. return 0;
  37. }
  38. LL rd(void) {
  39. LL x=0,f=1; char c=getchar();
  40. while (!isdigit(c)) {
  41. if (c=='-') f=-1;
  42. c=getchar();
  43. }
  44. while (isdigit(c)) {
  45. x=x*10+c-'0';
  46. c=getchar();
  47. }
  48. return x*f;
  49. }

代码2:快速沃尔什变换

  1. #include <cstdio>
  2. #include <cctype>
  3. #define F(i,a,b) for (int i=(a);i<=(b);i++)
  4. #define LL unsigned int
  5. LL rd(void);
  6. const int N=32;
  7. const int S=1048576;
  8. int n,nk;
  9. LL f[S];
  10. LL g[S];
  11. LL h[S];
  12. LL ans;
  13. void FWT(LL *a,int nk) {
  14. for (int i=2;i<=nk;i<<=1)
  15. for (int j=0;j<nk;j+=i)
  16. F(k,0,i/2-1) {
  17. LL x=a[j+k];
  18. LL y=a[j+k+i/2];
  19. a[j+k]=x;
  20. a[j+k+i/2]=x+y;
  21. }
  22. }
  23. void DWT(LL *a,int nk) {
  24. for (int i=2;i<=nk;i<<=1)
  25. for (int j=0;j<nk;j+=i)
  26. F(k,0,i/2-1) {
  27. LL x=a[j+k];
  28. LL y=a[j+k+i/2];
  29. a[j+k]=x;
  30. a[j+k+i/2]=y-x;
  31. }
  32. }
  33. int main(void) {
  34. #ifndef ONLINE_JUDGE
  35. freopen("A.in","r",stdin);
  36. freopen("A.out","w",stdout);
  37. #endif
  38. n=rd();
  39. nk=(1<<n);
  40. F(i,0,nk-1)
  41. f[i]=rd();
  42. F(i,0,nk-1)
  43. g[i]=rd();
  44. FWT(f,nk);
  45. FWT(g,nk);
  46. F(i,0,nk-1)
  47. h[i]=f[i]*g[i];
  48. DWT(h,nk);
  49. F(i,0,nk-1)
  50. ans+=h[i]*(i+1);
  51. printf("%u\n",ans);
  52. return 0;
  53. }
  54. LL rd(void) {
  55. LL x=0,f=1; char c=getchar();
  56. while (!isdigit(c)) {
  57. if (c=='-') f=-1;
  58. c=getchar();
  59. }
  60. while (isdigit(c)) {
  61. x=x*10+c-'0';
  62. c=getchar();
  63. }
  64. return x*f;
  65. }

【xsy1085】Data - 凸包

分析

注意到,最终答案的情形必然是这样的:我们过两个点作一条直线,一个人巡查直线左边的所有点,一个人巡查右边的所有点,对应左边有面积,右边有面积,求凸包,通过分割成三角形的方法计算多边形面积。

代码

  1. #include <cstdio>
  2. #include <cctype>
  3. #include <cmath>
  4. #include <algorithm>
  5. using namespace std;
  6. #define F(i,a,b) for (int i=(a);i<=(b);i++)
  7. #define D(i,a,b) for (int i=(a);i>=(b);i--)
  8. #define LD long double
  9. int rd(void);
  10. const int N=64;
  11. const LD MAX=1e30;
  12. int n;
  13. struct point {
  14. LD x,y;
  15. point(LD _x=0,LD _y=0) {
  16. x=_x,y=_y;
  17. }
  18. friend point operator - (point a,point b) {
  19. return point(a.x-b.x,a.y-b.y);
  20. }
  21. friend LD operator * (point a,point b) {
  22. return a.x*b.x+a.y*b.y;
  23. }
  24. friend LD operator ^ (point a,point b) {
  25. return a.x*b.y-a.y*b.x;
  26. }
  27. friend int operator < (point a,point b) {
  28. if (a.x!=b.x)
  29. return a.x<b.x;
  30. else return a.y<b.y;
  31. }
  32. void Read(void) {
  33. x=(LD)rd();
  34. y=(LD)rd();
  35. }
  36. }p[N];
  37. point stk[N]; int top;
  38. point q1[N]; int len1;
  39. point q2[N]; int len2;
  40. point c[N]; int tc;
  41. LD ans;
  42. void Polygon(point *p,int n) {
  43. //n>=1
  44. sort(p+1,p+n+1);
  45. while (len1>0)
  46. q1[len1--]=point();
  47. F(i,1,n) {
  48. while (len1>=2) {
  49. if (((q1[len1]-q1[len1-1])^(p[i]-q1[len1-1]))<=0)
  50. q1[len1--]=point();
  51. else break;
  52. }
  53. q1[++len1]=p[i];
  54. }
  55. while (len2>0)
  56. q2[len2--]=point();
  57. D(i,n,1) {
  58. while (len2>=2) {
  59. if (((q2[len2]-q2[len2-1])^(p[i]-q2[len2-1]))<=0)
  60. q2[len2--]=point();
  61. else break;
  62. }
  63. q2[++len2]=p[i];
  64. }
  65. while (top>0)
  66. stk[top--]=point();
  67. F(i,1,len1)
  68. stk[++top]=q1[i];
  69. F(i,2,len2-1)
  70. stk[++top]=q2[i];
  71. }
  72. LD dis(point a,point b) {
  73. return sqrt((a-b)*(a-b));
  74. }
  75. LD get(point a,point b,point c) {
  76. LD x=dis(a,b);
  77. LD y=dis(b,c);
  78. LD z=dis(c,a);
  79. LD p=(x+y+z)/2;
  80. return sqrt(p*(p-x)*(p-y)*(p-z));
  81. }
  82. LD Calc(void) {
  83. if (top<=2)
  84. return 0;
  85. LD sum=0;
  86. F(i,2,top-1) {
  87. LD t=get(stk[1],stk[i],stk[i+1]);
  88. sum+=t;
  89. }
  90. return sum;
  91. }
  92. void Split(point s,point t,int kd) {
  93. /*
  94. kd=0:左边,包括两点及线上的点
  95. kd=1:右边
  96. */
  97. while (tc>0)
  98. c[tc--]=point();
  99. F(i,1,n)
  100. if (kd==(((t-s)^(p[i]-s))<0))
  101. c[++tc]=p[i];
  102. }
  103. int main(void) {
  104. #ifndef ONLINE_JUDGE
  105. freopen("B.in","r",stdin);
  106. freopen("B.out","w",stdout);
  107. #endif
  108. n=rd();
  109. F(i,1,n)
  110. p[i].Read();
  111. ans=MAX;
  112. F(i,1,n)
  113. F(j,1,n) {
  114. Split(p[i],p[j],0);
  115. Polygon(c,tc);
  116. LD t=Calc();
  117. Split(p[i],p[j],1);
  118. Polygon(c,tc);
  119. t=max(t,Calc());
  120. ans=min(ans,t);
  121. }
  122. printf("%0.6Lf\n",ans);
  123. return 0;
  124. }
  125. int rd(void) {
  126. int x=0,f=1; char c=getchar();
  127. while (!isdigit(c)) {
  128. if (c=='-') f=-1;
  129. c=getchar();
  130. }
  131. while (isdigit(c)) {
  132. x=x*10+c-'0';
  133. c=getchar();
  134. }
  135. return x*f;
  136. }

【xsy1086】Version - 树链剖分+可持久化线段树维护等差数列

代码

  1. #include <cstdio>
  2. #include <cctype>
  3. #include <algorithm>
  4. #include <vector>
  5. using namespace std;
  6. #define F(i,a,b) for (int i=(a);i<=(b);i++)
  7. #define fore(v,x) for (vector<int>::iterator v=g[x].begin();v!=g[x].end();v++)
  8. #define LL long long
  9. int rd(void);
  10. char rdc(void);
  11. int trans(int u,LL ans,int n);
  12. int trans_w(int u,LL ans,int tot);
  13. const int N=131072;
  14. const int M=20000000;
  15. int n,m;
  16. vector<int> g[N];
  17. int pre[N],siz[N],son[N],dep[N];
  18. int dfn[N],ind,top[N];
  19. int tot;
  20. int rt[N],tms,now_rt;
  21. struct Tree {
  22. int lc,rc;
  23. int cnt;
  24. LL add,del;
  25. //cnt表示区间公差,第一项为0
  26. LL sum;
  27. }tr[M];
  28. void Find(int x) {
  29. siz[x]=1;
  30. fore(v,x)
  31. if (pre[x]!=*v) {
  32. pre[*v]=x;
  33. dep[*v]=dep[x]+1;
  34. Find(*v);
  35. siz[x]+=siz[*v];
  36. if (siz[son[x]]<siz[*v])
  37. son[x]=*v;
  38. }
  39. }
  40. void Split(int x,int anc) {
  41. dfn[x]=++ind;
  42. top[x]=anc;
  43. if (son[x]>0)
  44. Split(son[x],anc);
  45. fore(v,x)
  46. if (*v!=pre[x]&&*v!=son[x])
  47. Split(*v,*v);
  48. }
  49. int LCA(int x,int y) {
  50. while (top[x]!=top[y]) {
  51. if (dep[top[x]]<dep[top[y]])
  52. swap(x,y);
  53. x=pre[top[x]];
  54. }
  55. return dep[x]<dep[y]?x:y;
  56. }
  57. void Update(int x) {
  58. int lc=tr[x].lc,rc=tr[x].rc;
  59. tr[x].cnt=tr[lc].cnt+tr[rc].cnt;
  60. tr[x].sum=tr[lc].sum+tr[rc].sum;
  61. tr[x].sum+=tr[x].add*tr[x].cnt;
  62. tr[x].sum+=tr[x].del*(tr[x].cnt-1)*tr[x].cnt>>1;
  63. }
  64. int Build(int l,int r) {
  65. int x=++tot;
  66. tr[x].cnt=r-l+1;
  67. if (l!=r) {
  68. int mid=(l+r)>>1;
  69. tr[x].lc=Build(l,mid);
  70. tr[x].rc=Build(mid+1,r);
  71. }
  72. return x;
  73. }
  74. int Copynode(int frm) {
  75. int x=++tot;
  76. tr[x]=tr[frm];
  77. return x;
  78. }
  79. int Change(int frm,int l,int r,int ql,int qr,LL a,LL b) {
  80. if (ql>r||qr<l)
  81. return frm;
  82. int x=Copynode(frm);
  83. if (ql<=l&&r<=qr) {
  84. tr[x].add+=a+b*(l-ql);
  85. tr[x].del+=b;
  86. tr[x].sum+=(a+b*(l-ql))*tr[x].cnt;
  87. tr[x].sum+=b*(tr[x].cnt-1)*tr[x].cnt>>1;
  88. return x;
  89. }
  90. int mid=(l+r)>>1;
  91. tr[x].lc=Change(tr[frm].lc,l,mid,ql,qr,a,b);
  92. tr[x].rc=Change(tr[frm].rc,mid+1,r,ql,qr,a,b);
  93. Update(x);
  94. return x;
  95. }
  96. LL Query(int x,int l,int r,int ql,int qr) {
  97. if (ql>r||qr<l)
  98. return 0;
  99. if (ql<=l&&r<=qr)
  100. return tr[x].sum;
  101. int mid=(l+r)>>1;
  102. int aL=max(l,ql);
  103. int aR=min(r,qr);
  104. int cnt=aR-aL+1;
  105. LL ans=tr[x].add*cnt+(tr[x].del*(aL-l+aR-l)*cnt>>1);
  106. ans+=Query(tr[x].lc,l,mid,ql,qr);
  107. ans+=Query(tr[x].rc,mid+1,r,ql,qr);
  108. return ans;
  109. }
  110. void Change_Path(int u,int v,int a,int b) {
  111. int anc=LCA(u,v);
  112. int tu=u,tv=v;
  113. while (top[u]!=top[anc]) {
  114. int dis=dep[tu]-dep[top[u]];
  115. now_rt=Change(now_rt,1,n,dfn[top[u]],dfn[u],a+b*dis,-b);
  116. u=pre[top[u]];
  117. }
  118. while (top[v]!=top[anc]) {
  119. int dis=dep[tu]+dep[top[v]]-dep[anc]-dep[anc];
  120. now_rt=Change(now_rt,1,n,dfn[top[v]],dfn[v],a+b*dis,b);
  121. v=pre[top[v]];
  122. }
  123. if (u==anc) {
  124. int dis=dep[tu]-dep[anc];
  125. now_rt=Change(now_rt,1,n,dfn[u],dfn[v],a+b*dis,b);
  126. }
  127. else {
  128. int dis=dep[tu]-dep[anc];
  129. now_rt=Change(now_rt,1,n,dfn[v],dfn[u],a+b*dis,-b);
  130. }
  131. rt[++tms]=now_rt;
  132. }
  133. LL Query_Path(int u,int v) {
  134. int anc=LCA(u,v);
  135. LL sum=0;
  136. while (top[u]!=top[anc]) {
  137. sum+=Query(now_rt,1,n,dfn[top[u]],dfn[u]);
  138. u=pre[top[u]];
  139. }
  140. while (top[v]!=top[anc]) {
  141. sum+=Query(now_rt,1,n,dfn[top[v]],dfn[v]);
  142. v=pre[top[v]];
  143. }
  144. if (u==anc)
  145. sum+=Query(now_rt,1,n,dfn[u],dfn[v]);
  146. else sum+=Query(now_rt,1,n,dfn[v],dfn[u]);
  147. return sum;
  148. }
  149. void Roll(int w) {
  150. now_rt=rt[w];
  151. }
  152. int main(void) {
  153. #ifndef ONLINE_JUDGE
  154. freopen("a.in","r",stdin);
  155. freopen("a.out","w",stdout);
  156. #endif
  157. n=rd(),m=rd();
  158. F(i,1,n-1) {
  159. int u=rd(),v=rd();
  160. g[u].push_back(v);
  161. g[v].push_back(u);
  162. }
  163. Find(1);
  164. Split(1,1);
  165. now_rt=rt[0]=Build(1,n);
  166. LL ans=0;
  167. F(i,1,m) {
  168. char c=rdc();
  169. if (c=='c') {
  170. int u=rd(),v=rd(),a=rd(),b=rd();
  171. u=trans(u,ans,n);
  172. v=trans(v,ans,n);
  173. Change_Path(u,v,a,b);
  174. }
  175. else if (c=='q') {
  176. int u=rd(),v=rd();
  177. u=trans(u,ans,n);
  178. v=trans(v,ans,n);
  179. ans=Query_Path(u,v);
  180. printf("%lld\n",ans);
  181. }
  182. else if (c=='r') {
  183. int w=rd();
  184. w=trans_w(w,ans,tms);
  185. Roll(w);
  186. }
  187. }
  188. return 0;
  189. }
  190. int rd(void) {
  191. int x=0,f=1; char c=getchar();
  192. while (!isdigit(c)) {
  193. if (c=='-') f=-1;
  194. c=getchar();
  195. }
  196. while (isdigit(c)) {
  197. x=x*10+c-'0';
  198. c=getchar();
  199. }
  200. return x*f;
  201. }
  202. char rdc(void) {
  203. char c=getchar();
  204. while (!isalpha(c))
  205. c=getchar();
  206. return c;
  207. }
  208. int trans(int u,LL ans,int n) {
  209. return (u+ans)%n+1;
  210. }
  211. int trans_w(int w,LL ans,int tot) {
  212. return (w+ans)%(tot+1);
  213. }

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注