[关闭]
@LittleRewriter 2017-10-08T02:20:19.000000Z 字数 6904 阅读 799

D2讲题


T1

60分:打表
100分:
使
如果强行假定a<=b<=c,那么这一答案就是这样的。
由于,可以大量减少枚举次数。

由于,所以,直接加上即可

  1. for(int a=1;a*a*a<=n;++a)
  2. for(int b=a;b*b<=n/a;++b)
  3. ans+=n/a/b-b;

复杂度
问题是如果一样,那么:
三个数都一样,枚举一下;
两个数都一样,不妨假设b=c
从而枚举b的值,可以枚举出来
将这两种情况剪掉即可
可以用这个自适应win/linux输出longlong:

  1. #ifdef WIN32
  2. #define LL "%I64d"
  3. #else
  4. #define LL "%lld"
  5. #endif
  6. /.../
  7. printf("LL",a);

标程:

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. using namespace std;
  5. long long n;
  6. #ifdef unix
  7. #define LL "%lld"
  8. #else
  9. #define LL "%I64d"
  10. #endif
  11. //64位都可以
  12. int main()
  13. {
  14. freopen("a.in","r",stdin);
  15. freopen("a.out","w",stdout);
  16. scanf(LL,&n);
  17. long long ans=0,tmp=0;
  18. for (long long a=1,v;a*a<=(v=n/a);a++,ans++)
  19. for (long long b=a+1;b*b<=v;b++)
  20. tmp+=n/(a*b)-b;
  21. ans+=tmp*6;
  22. tmp=0;
  23. for (long long a=1,v;(v=a*a)<=n;a++)
  24. {
  25. tmp+=n/v;
  26. if (a*a<=n/a) tmp--;
  27. }
  28. ans+=tmp*3;
  29. printf(LL "\n",ans);
  30. return 0;
  31. }

T3

30分:
对每一个值都可以算出来加成
这是可以优先考虑贡献小的搜
提高搜到最优解的速度
100分:
由于“昨天考过的今天都不考”
所以这是一道DP题
我们需要考虑卡包和卡包的距离与玄学值和玄学值的距离(例如,影响5的只有4,5,6 3个值)
设计状态:这样的九维状态
表示1-i的所有玄学值已经考虑过之后的结果,使用了这些玄学值即每一个卡包用了多少玄学值。由于只能有最多5个所以这几个值都<=5
接下来的代表第p包卡中有无玄学值i,两维
f[30][5][5][5][5][2][2][2][2]空间复杂度300000
这里枚举来确定加成。由于最后四维状态确定了有无i,算一下就行了(并不
嗯,标程,请感受一下来自dp的恶意:

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. #define now pre[a][b][c][d][e][s1][s2][s3][s4]
  7. #define dis(a,b,c,d) (abs(a-c)+abs(b-d))
  8. const int INF=0x3f3f3f3f;
  9. int A,B,C,D,E,num[10][10],value[10][10][10],delta[10][10][40],dp[31][6][6][6][6][2][2][2][2];
  10. char s[500];
  11. bool map[6][6][6][6];
  12. int main()
  13. {
  14. freopen("c.in","r",stdin);
  15. freopen("c.out","w",stdout);
  16. scanf("%d%d%d%d%d",&A,&B,&C,&D,&E);
  17. for (int a=0;a<6;a++)
  18. {
  19. scanf("%s",s);
  20. int p=0;
  21. for (int b=0;b<6;b++)
  22. {
  23. int px=p;
  24. while (s[px]!=']')
  25. px++;
  26. p++;
  27. num[a][b]=s[p]-'0';
  28. p++;
  29. p++;
  30. for (int c=1;c<=num[a][b];c++)
  31. {
  32. int v=0;
  33. while (s[p]>='0' && s[p]<='9')
  34. {
  35. v=v*10+s[p]-'0';
  36. p++;
  37. }
  38. value[a][b][c]=v;
  39. p++;
  40. }
  41. p=px+1;
  42. }
  43. }
  44. int base=0;
  45. for (int a=0;a<6;a++)
  46. for (int b=0;b<6;b++)
  47. if (a>=2 && a<=3 && b>=2 && b<=3) ;
  48. else
  49. {
  50. sort(value[a][b]+1,value[a][b]+num[a][b]+1);
  51. for (int c=2;c<=num[a][b];c++)
  52. if (value[a][b][c]-value[a][b][c-1]==1) base+=A;
  53. for (int c=2;c<=3;c++)
  54. for (int d=2;d<=3;d++)
  55. {
  56. if (dis(a,b,c,d)==1)
  57. {
  58. for (int e=1;e<=num[a][b];e++)
  59. {
  60. delta[c][d][value[a][b][e]]+=B;
  61. delta[c][d][value[a][b][e]-1]+=C;
  62. delta[c][d][value[a][b][e]+1]+=C;
  63. }
  64. }
  65. if (dis(a,b,c,d)==2)
  66. {
  67. for (int e=1;e<=num[a][b];e++)
  68. {
  69. delta[c][d][value[a][b][e]]+=D;
  70. delta[c][d][value[a][b][e]-1]+=E;
  71. delta[c][d][value[a][b][e]+1]+=E;
  72. }
  73. }
  74. }
  75. for (int c=0;c<6;c++)
  76. for (int d=0;d<6;d++)
  77. if (dis(a,b,c,d)<=2 && (c!=a || d!=b) && !map[a][b][c][d])
  78. {
  79. map[a][b][c][d]=map[c][d][a][b]=true;
  80. if (c>=2 && c<=3 && d>=2 && d<=3) ;
  81. else
  82. {
  83. int dist=dis(a,b,c,d);
  84. for (int e=1;e<=num[a][b];e++)
  85. for (int f=1;f<=num[c][d];f++)
  86. {
  87. if (abs(value[a][b][e]-value[c][d][f])==0)
  88. {
  89. if (dist==1) base+=B;
  90. else base+=D;
  91. }
  92. if (abs(value[a][b][e]-value[c][d][f])==1)
  93. {
  94. if (dist==1) base+=C;
  95. else base+=E;
  96. }
  97. }
  98. }
  99. }
  100. }
  101. memset(dp,0x3f,sizeof(dp));
  102. dp[0][0][0][0][0][0][0][0][0]=base;
  103. for (int a=0;a<30;a++)
  104. for (int b=0;b<=num[2][2];b++)
  105. for (int c=0;c<=num[2][3];c++)
  106. for (int d=0;d<=num[3][2];d++)
  107. for (int e=0;e<=num[3][3];e++)
  108. for (int s1=0;s1<=1;s1++)
  109. for (int s2=0;s2<=1;s2++)
  110. for (int s3=0;s3<=1;s3++)
  111. for (int s4=0;s4<=1;s4++)
  112. if (dp[a][b][c][d][e][s1][s2][s3][s4]!=INF)
  113. {
  114. int v=dp[a][b][c][d][e][s1][s2][s3][s4];
  115. for (int sx1=0;sx1<=(b!=num[2][2]);sx1++)
  116. for (int sx2=0;sx2<=(c!=num[2][3]);sx2++)
  117. for (int sx3=0;sx3<=(d!=num[3][2]);sx3++)
  118. for (int sx4=0;sx4<=(e!=num[3][3]);sx4++)
  119. {
  120. int wmt=0;
  121. if (sx1)
  122. {
  123. wmt+=delta[2][2][a+1];
  124. if (s1) wmt+=A;
  125. if (s2) wmt+=C;
  126. if (s3) wmt+=C;
  127. if (s4) wmt+=E;
  128. }
  129. if (sx2)
  130. {
  131. wmt+=delta[2][3][a+1];
  132. if (s1) wmt+=C;
  133. if (s2) wmt+=A;
  134. if (s3) wmt+=E;
  135. if (s4) wmt+=C;
  136. }
  137. if (sx3)
  138. {
  139. wmt+=delta[3][2][a+1];
  140. if (s1) wmt+=C;
  141. if (s2) wmt+=E;
  142. if (s3) wmt+=A;
  143. if (s4) wmt+=C;
  144. }
  145. if (sx4)
  146. {
  147. wmt+=delta[3][3][a+1];
  148. if (s1) wmt+=E;
  149. if (s2) wmt+=C;
  150. if (s3) wmt+=C;
  151. if (s4) wmt+=A;
  152. }
  153. if (sx1 && sx2) wmt+=B;
  154. if (sx1 && sx3) wmt+=B;
  155. if (sx1 && sx4) wmt+=D;
  156. if (sx2 && sx3) wmt+=D;
  157. if (sx2 && sx4) wmt+=B;
  158. if (sx3 && sx4) wmt+=B;
  159. int &t=dp[a+1][b+sx1][c+sx2][d+sx3][e+sx4][sx1][sx2][sx3][sx4];
  160. if (t>v+wmt) t=v+wmt;
  161. }
  162. }
  163. int ans=INF;
  164. for (int a=0;a<=1;a++)
  165. for (int b=0;b<=1;b++)
  166. for (int c=0;c<=1;c++)
  167. for (int d=0;d<=1;d++)
  168. ans=min(ans,dp[30][num[2][2]][num[2][3]][num[3][2]][num[3][3]][a][b][c][d]);
  169. printf("%d\n",ans);
  170. return 0;
  171. }

T2

最优策略:朝着对面走先抢
因此有三个阶段:
1)遇上
2)轮流从大到小抢子树
3)遍历子树
因此1)是一大难点,采用倍增求LCA
假设两点距离为l,若l为偶数则走l/2,否则走
一定有一个人始终向上走,一个人某一阶段以后从上往下走,算出到LCA的距离即可。
标程:

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. const int maxn=100010;
  7. int n,m,en,z[maxn*3],f[maxn][20],q[maxn],depth[maxn],sum[maxn*3][2],fd[maxn],start[maxn],end[maxn],value[maxn];
  8. struct edge
  9. {
  10. int e,d;
  11. edge *next;
  12. }*v[maxn],ed[maxn<<1];
  13. void add_edge(int s,int e,int d)
  14. {
  15. en++;
  16. ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->d=d;
  17. }
  18. int get(int p,int d)
  19. {
  20. if (d==-1) return p;
  21. int x=0;
  22. while (d)
  23. {
  24. if (d&1) p=f[p][x];
  25. d>>=1;
  26. x++;
  27. }
  28. return p;
  29. }
  30. int get_lca(int p1,int p2)
  31. {
  32. if (depth[p1]<depth[p2]) swap(p1,p2);
  33. p1=get(p1,depth[p1]-depth[p2]);
  34. int x=0;
  35. while (p1!=p2)
  36. {
  37. if (!x || f[p1][x]!=f[p2][x])
  38. {
  39. p1=f[p1][x];
  40. p2=f[p2][x];
  41. x++;
  42. }
  43. else x--;
  44. }
  45. return p1;
  46. }
  47. int calc(int p1,int p2)
  48. {
  49. if (p1==f[p2][0]) return value[1]-value[p2];
  50. else return value[p1]+fd[p1];
  51. }
  52. int calcp(int p,int v)
  53. {
  54. int l=start[p]-1,r=end[p];
  55. while (l+1!=r)
  56. {
  57. int m=(l+r)>>1;
  58. if (v>z[m]) l=m;
  59. else r=m;
  60. }
  61. return r;
  62. }
  63. int main()
  64. {
  65. freopen("b.in","r",stdin);
  66. freopen("b.out","w",stdout);
  67. scanf("%d%d",&n,&m);
  68. int tot=0;
  69. for (int a=1;a<n;a++)
  70. {
  71. int s,e,d;
  72. scanf("%d%d%d",&s,&e,&d);
  73. tot+=d;
  74. add_edge(s,e,d);
  75. add_edge(e,s,d);
  76. }
  77. depth[1]=1;
  78. int front=1,tail=1;
  79. q[1]=1;
  80. for (;front<=tail;)
  81. {
  82. int now=q[front++];
  83. for (edge *e=v[now];e;e=e->next)
  84. if (!depth[e->e])
  85. {
  86. depth[e->e]=depth[now]+1;
  87. fd[e->e]=e->d;
  88. f[e->e][0]=now;
  89. int p=now,x=0;
  90. while (f[p][x])
  91. {
  92. f[e->e][x+1]=f[p][x];
  93. p=f[p][x];
  94. x++;
  95. }
  96. q[++tail]=e->e;
  97. }
  98. }
  99. int cnt=0;
  100. for (int a=n;a>=1;a--)
  101. {
  102. int now=q[a];
  103. start[now]=cnt+1;
  104. for (edge *e=v[now];e;e=e->next)
  105. if (depth[e->e]==depth[now]+1)
  106. {
  107. z[++cnt]=value[e->e]+e->d;
  108. value[now]+=value[e->e]+e->d;
  109. }
  110. z[++cnt]=tot-value[now];
  111. end[now]=cnt;
  112. sort(z+start[now],z+end[now]+1);
  113. sum[end[now]][0]=z[end[now]];
  114. sum[end[now]][1]=0;
  115. for (int a=end[now]-1;a>=start[now];a--)
  116. {
  117. sum[a][0]=sum[a+1][0];
  118. sum[a][1]=sum[a+1][1];
  119. if ((a&1)==(end[now]&1)) sum[a][0]+=z[a];
  120. else sum[a][1]+=z[a];
  121. }
  122. cnt++;
  123. }
  124. for (int a=1;a<=m;a++)
  125. {
  126. int p1,p2;
  127. scanf("%d%d",&p1,&p2);
  128. int lca=get_lca(p1,p2);
  129. int dist=depth[p1]+depth[p2]-2*depth[lca];
  130. int delta=dist/2+(dist&1);
  131. int px,px1,px2;
  132. if (depth[p1]-depth[lca]<delta) px=get(p2,dist-delta);
  133. else px=get(p1,delta);
  134. if (depth[p1]-depth[lca]<delta-1) px1=get(p2,dist-delta+1);
  135. else px1=get(p1,delta-1);
  136. if (depth[p2]-depth[lca]<dist-delta-1) px2=get(p1,delta+1);
  137. else px2=get(p2,dist-delta-1);
  138. int ans=0;
  139. if (p1==px)
  140. {
  141. if (p2==px) ans=sum[start[px]][0];
  142. else
  143. {
  144. int v2=calc(px2,px);
  145. int p=calcp(px,v2);
  146. ans=sum[p+1][0]+sum[start[px]][1]-sum[p][1];
  147. }
  148. }
  149. else
  150. {
  151. if (p2==px)
  152. {
  153. int v1=calc(px1,px);
  154. int p=calcp(px,v1);
  155. ans=v1+sum[p+1][1]+sum[start[px]][0]-sum[p][0];
  156. }
  157. else
  158. {
  159. int v1=calc(px1,px);
  160. int pp1=calcp(px,v1);
  161. int v2=calc(px2,px);
  162. int pp2=calcp(px,v2);
  163. if (pp2==pp1) pp2++;
  164. if (pp1>pp2) swap(pp1,pp2);
  165. ans=v1+sum[pp2+1][dist&1]+sum[pp1+1][1-(dist&1)]-sum[pp2][1-(dist&1)]+sum[start[px]][dist&1]-sum[pp1][dist&1];
  166. }
  167. }
  168. printf("%d\n",ans);
  169. }
  170. return 0;
  171. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注