[关闭]
@happyforever 2018-10-29T14:27:16.000000Z 字数 8528 阅读 520

10.23晚上解题报告

解题报告 清北学堂


图片.png

各题状况

期望得分:
实际得分:

T1

写了半小时的KMP
调了一个半小时的AC自动机
发现不会改就放过了
hash有想过但是实在怕被卡就没有写
然后号上午写了一份unsigned long long自然溢出的代码过了。。。

T2

因为输入数据比较大,有的人没写快读就很亏,然后老师开了的时限
。。。。
我也过不了。。。
小数据范围没写,只写了特殊性质,然后了。

数据锅了hhhh
部分分的数据范围与题目给的范围不一样

T3

Floyd
分每次暴搜

题目及考场代码

T1

图片.png
图片.png
图片.png

  1. /*
  2. * 有人说是AC自动机。。
  3. * 吔
  4. * 我只会KMP是不是凉了2333
  5. * O(Ln),最坏情况O(1e9)
  6. */
  7. #include <cstdio>
  8. #include <cstring>
  9. const int N=1e5+1;
  10. int L,n,m,next[21];
  11. char s[N],ss[N/10+1][21];
  12. bool flag=true;
  13. void getNext(char *ss)
  14. {
  15. for(int j=0,i=1;i<m;++i)
  16. {
  17. while(j && ss[i]!=ss[j])
  18. j=next[j];
  19. if(ss[i]==ss[j])
  20. next[i+1]=++j;
  21. else next[i+1]=0;
  22. }
  23. }
  24. void KMP(char *ss)
  25. {
  26. for(int j=0,i=0;i<L;++i)
  27. {
  28. while(j && s[i]!=ss[j])
  29. j=next[j];
  30. if(s[i]==ss[j])
  31. ++j;
  32. if(j==m)
  33. {
  34. flag=false;
  35. printf("%d\n",i-m+2);
  36. return ;
  37. }
  38. }
  39. }
  40. int main()
  41. {
  42. freopen("monitor.in","r",stdin);
  43. freopen("monitor.out","w",stdout);
  44. scanf("%d%d%d",&L,&n,&m);
  45. for(int i=1;i<=n;++i)
  46. scanf("%s",ss[i]);
  47. scanf("%s",s);
  48. for(int i=1;i<=n;++i)
  49. {
  50. getNext(ss[i]);
  51. KMP(ss[i]);
  52. if(!flag)goto E;
  53. }
  54. if(flag)puts("no");
  55. E: fclose(stdin),fclose(stdout);
  56. return 0;
  57. }

T2

图片.png
图片.png
图片.png

  1. /*
  2. * 多加了边就会形成环
  3. * 不存在k=0考虑LCA求解
  4. * 有一个环的话
  5. */
  6. #include <cstdio>
  7. #include <iostream>
  8. inline int read()
  9. {
  10. int n=0,w=1;register char c=getchar();
  11. while(c<'0' || c>'9'){if(c=='-')w=-1;c=getchar();}
  12. while(c>='0' && c<='9')n=n*10+c-'0',c=getchar();
  13. return n*w;
  14. }
  15. const int N=1e5+1;
  16. int n,q,tot,head[N];
  17. int val[N],deep[N],fa[N],son[N],size[N],top[N],idx[N];
  18. struct Edge{
  19. int v,w,nxt;
  20. }edge[N];
  21. inline void add(int w,int v,int u)
  22. {
  23. edge[++tot]=(Edge){v, w,head[u]};head[u]=tot;
  24. edge[++tot]=(Edge){u,-w,head[v]};head[v]=tot;
  25. }
  26. void dfs1(int now)
  27. {
  28. size[now]=1;
  29. for(int v,i=head[now];i;i=edge[i].nxt)
  30. if((v=edge[i].v)!=fa[now])
  31. {
  32. deep[v]=deep[now]+1;
  33. val[v]=edge[i].w;
  34. fa[v]=now;
  35. dfs1(v);
  36. size[now]+=size[v];
  37. if(size[son[now]]<size[v])
  38. son[now]=v;
  39. }
  40. }
  41. void dfs2(int now,int tp)
  42. {
  43. top[now]=tp;
  44. if(!son[now])return ;
  45. dfs2(son[now],tp);
  46. for(int i=head[now];i;i=edge[i].nxt)
  47. if(edge[i].v!=fa[now])
  48. dfs2(edge[i].v,edge[i].v);
  49. }
  50. inline int Lca(int x,int y)
  51. {
  52. while(top[x]!=top[y])
  53. {
  54. if(deep[top[x]]<deep[top[y]])
  55. std::swap(x,y);
  56. x=fa[top[x]];
  57. }
  58. return deep[x]>deep[y]?y:x;
  59. }
  60. inline int query(int x,int y)
  61. {
  62. int lca=Lca(x,y);
  63. long long ans=0;
  64. while(x!=lca)
  65. {
  66. ans-=val[x];
  67. x=fa[x];
  68. }
  69. while(y!=lca)
  70. {
  71. ans+=val[y];
  72. y=fa[y];
  73. }
  74. // printf("%d",ans);
  75. return ans;
  76. }
  77. int main()
  78. {
  79. freopen("lab.in","r",stdin);
  80. freopen("lab.out","w",stdout);
  81. n=read(),q=read();
  82. for(int i=1;i<n;++i)
  83. add(read(),read(),read());
  84. dfs1(1);
  85. dfs2(1,1);
  86. int k,x,y,z;
  87. while(q--)
  88. {
  89. k=read(),x=read(),y=read(),z=read();
  90. puts(query(x,y)==z?"yes":"no");
  91. }
  92. fclose(stdin),fclose(stdout);
  93. return 0;
  94. }

T3

图片.png
图片.png
图片.png

  1. /*
  2. * 40分可以floyd
  3. * 考虑对每个点,维护其到其子树内各点的奇、偶路径长度和
  4. */
  5. #include <cstdio>
  6. #include <cstring>
  7. const int N=1e5+1;
  8. int n,q,tot,head[N];
  9. struct Edge{
  10. int v,w,nxt;
  11. }edge[N<<1];
  12. long long ans[2];
  13. inline void add(int w,int v,int u)
  14. {
  15. edge[++tot]=(Edge){v,w,head[u]};head[u]=tot;
  16. edge[++tot]=(Edge){u,w,head[v]};head[v]=tot;
  17. }
  18. inline int read()
  19. {
  20. int n=0,w=1;register char c=getchar();
  21. while(c<'0' || c>'9'){if(c=='-')w=-1;c=getchar();}
  22. while(c>='0' && c<='9')n=n*10+c-'0',c=getchar();
  23. return n*w;
  24. }
  25. void dfs(int now,int fa,long long w)
  26. {
  27. ans[w&1]+=w;
  28. for(int v,i=head[now];i;i=edge[i].nxt)
  29. if((v=edge[i].v)!=fa)
  30. dfs(v,now,edge[i].w+w);
  31. }
  32. int main()
  33. {
  34. freopen("civilization.in","r",stdin);
  35. freopen("civilization.out","w",stdout);
  36. n=read(),q=read();
  37. for(int i=1;i<n;++i)
  38. add(read(),read(),read());
  39. int x;
  40. while(q--)
  41. {
  42. x=read();ans[1]=ans[0]=0;
  43. dfs(x,x,0);
  44. printf("%I64d %I64d\n",ans[1],ans[0]);
  45. }
  46. fclose(stdin),fclose(stdout);
  47. return 0;
  48. }

正解及代码

T1

KMP,最坏复杂度可以得

std::string里面的find函数,因为每次find是最坏复杂度的,所以最坏,也能

hash。。。某同学:“老师,会卡hash吗”。老师:“我有一晚上的时间”。

没有卡,都卡掉了

其他比较随意的也没有卡

std::map因为时间问题会一个点

  1. #include <set>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. int L,n,m;
  6. typedef unsigned long long LLU;
  7. const LLU mod=1000000000+7;
  8. const LLU mod2=1000000000+9;
  9. const LLU base = 131;
  10. LLU h[10005];
  11. LLU h2[10005];
  12. char s[100005];
  13. LLU gethash(char *s)
  14. {
  15. LLU ret = 0;
  16. for(int i=0;s[i];++i)
  17. ret=(ret*base+s[i])%mod;
  18. return ret;
  19. }
  20. LLU gethash2(char *s)
  21. {
  22. LLU ret=0;
  23. for(int i=0;s[i];++i)
  24. ret=(ret*base+s[i]) % mod2;
  25. return ret;
  26. }
  27. std::set<std::pair<LLU,LLU> > mingan;
  28. int main()
  29. {
  30. freopen("monitor.in", "r", stdin);
  31. freopen("monitor.out", "w", stdout);
  32. scanf("%d%d%d",&L,&n,&m);
  33. for(int i=1;i<=n;++i)
  34. {
  35. scanf("%s",s+1);
  36. h[i]=gethash(s+1);
  37. h2[i]=gethash2(s+1);
  38. mingan.insert(make_pair(h[i],h2[i]));
  39. }
  40. scanf("%s",s+1);
  41. LLU now=0,now2=0,basem=1,basem2=1;
  42. bool flag=0;
  43. for(int i=1;i<=m;++i)
  44. basem=basem*base%mod,basem2=basem2*base%mod2;
  45. for(int i=1;i<=L;++i)
  46. {
  47. now=(now*base+s[i])%mod;
  48. now2=(now2*base+s[i])%mod2;
  49. if(i>m)
  50. {
  51. now=((now-s[i-m]*basem%mod)+mod)%mod;
  52. now2=((now2-s[i-m]*basem2%mod2)+mod2)%mod2;
  53. }
  54. if(mingan.count(make_pair(now,now2))!=0)
  55. {
  56. printf("%d\n",i-m+1);
  57. flag=1;
  58. break;
  59. }
  60. }
  61. if(!flag)puts("no");
  62. return 0;
  63. }

T2

当没有的操作时,就是在树上求两点之间的路径长度是否等于某个值

通常的想法是

换个想法,假设现在有一棵树如下

图片.png

现在求的路径长度

表示从点到根节点的距离,那么就是蓝色线,是紫色线

图片.png

再考虑所代表的含义

图片.png

橙色的线段代表的路径,从指向

也就是的路径长度

由此,对于的数据,可以预处理,而后每次输出答案

对于,即只有一个环的数据,考虑环对答案的贡献

图片.png

考虑如上的一张图,询问是否有某长度的路径,的权值与是相反数

所以从走到再走回去只会增加(或减少)环的大小的时间

虽然没有给有两个(有两个环)的情况,但我们应该用它来考虑向正解的靠近

不妨先考虑两个环互不影响的情况

图片.png

假设第一个环的大小是,第二个环的大小是

那么就是要求同余方程是否有解

根据裴蜀定理,同余方程有解当且仅当

所以我们要求的就是上述方程是否有解

再考虑更一般的情况:可能有很多环

那么先求一遍每个点到根的路径,再在操作过程中对所有产生的环求其大小(假定有个环,大小分别为),询问时,一个数不能被拼出来当且仅当

  1. #include <cmath>
  2. #include <cstdio>
  3. #include <cstring>
  4. const int N=100001;
  5. int n,q,head[N],tot;
  6. struct Edge{
  7. int v,w,nxt;
  8. }edge[N<<1];
  9. inline void add(int w,int v,int u)
  10. {
  11. edge[++tot]=(Edge){v, w,head[u]};head[u]=tot;
  12. edge[++tot]=(Edge){u,-w,head[v]};head[v]=tot;
  13. }
  14. inline int read()
  15. {
  16. int n=0,w=1;register char c=getchar();
  17. while(c<'0' || c>'9'){if(c=='-')w=-1;c=getchar();}
  18. while(c>='0' && c<='9')n=n*10+c-'0',c=getchar();
  19. return n*w;
  20. }
  21. typedef long long LL;
  22. LL sum[100005];
  23. void dfs(int x,int fa)
  24. {
  25. for(int v,i=head[x];i;i=edge[i].nxt)
  26. if((v=edge[i].v)!=fa)
  27. {
  28. sum[edge[i].v]=sum[x]+edge[i].w;
  29. dfs(v,x);
  30. }
  31. }
  32. LL gcd(LL a, LL b)
  33. {return b==0?a:gcd(b,a%b);}
  34. int main()
  35. {
  36. freopen("lab.in","r",stdin);
  37. freopen("lab.out","w",stdout);
  38. n=read(),q=read();
  39. for(int i=1;i<n;++i)
  40. add(read(),read(),read());
  41. dfs(1,0);
  42. LL g=0;
  43. for(int i=0,k,x,y,t;i<q;++i)
  44. {
  45. k=read(),x=read(),y=read(),t=read();
  46. if(k==0)
  47. {
  48. if(!g)
  49. g=abs(sum[x]-sum[y]+t);
  50. else
  51. if(abs(sum[x]-sum[y]+t)%g!=0)
  52. g=gcd(g,abs(sum[x]-sum[y]+t));
  53. }
  54. else
  55. if(k==1)
  56. {
  57. if(sum[y]-sum[x]==t)//不需要环
  58. puts("yes");
  59. else
  60. if(g==0)//没有环
  61. puts("no");
  62. else
  63. if((t-(sum[y]-sum[x]))%g==0)
  64. puts("yes");
  65. else puts("no");
  66. }
  67. }
  68. fclose(stdin);fclose(stdout);
  69. return 0;
  70. }

T3

考虑求一个点的子树中所有点到这个点的权值和

  1. void dfs1(int x,int fa)
  2. {
  3. size[x]=1;
  4. for(int v,i=head[x];i;i=edge[i].nxt)
  5. if((v=edge[i].v)!=fa)
  6. {
  7. dfs1(v,x);
  8. size[x]+=size[v];
  9. f[x]+=f[v]+edge[i].w*size[v];
  10. }
  11. }

那么如果能够从父亲节点推到儿子节点就可以了

对每个点,把当前点的子树的贡献刨掉

  1. f2[1]=f[1];
  2. void dfs2(int x)
  3. {
  4. for(int v,i=head[x];i;i=edge[i].nxt)
  5. if((v=edge[i].v)!=fa)
  6. {
  7. f2[v] =f[v];
  8. f2[v]+=f2[x]-f[v]-edge[i].w*size[v]+edge[i].w*(size[1]-size[x]);
  9. dfs2(v,x);
  10. }
  11. }

另外注意在经过一条奇边之后,奇数路径和与偶数路径和要对换;经过一条偶边之后奇数路径和与偶数路径和仅仅数值变化不会对换

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. // 70%给开了int没开longlong
  5. const int N=100001;
  6. int n,q,head[N],tot;
  7. struct Edge{
  8. int v,w,nxt;
  9. }edge[N<<1];
  10. inline void add(int w,int v,int u)
  11. {
  12. edge[++tot]=(Edge){v, w,head[u]};head[u]=tot;
  13. edge[++tot]=(Edge){u,-w,head[v]};head[v]=tot;
  14. }
  15. inline int read()
  16. {
  17. int n=0,w=1;register char c=getchar();
  18. while(c<'0' || c>'9'){if(c=='-')w=-1;c=getchar();}
  19. while(c>='0' && c<='9')n=n*10+c-'0',c=getchar();
  20. return n*w;
  21. }
  22. typedef long long LL;
  23. LL f[2][N];
  24. LL ans[2][N];
  25. int siz[2][N];
  26. int siz2[2][N];
  27. void dfs1(int x,int fa)
  28. {
  29. siz[0][x]=1;
  30. for(int v,i=head[x];i;i=edge[i].nxt)
  31. {
  32. if((v=edge[i].v)==fa) continue;
  33. dfs1(v,x);
  34. if(edge[i].w&1)
  35. {
  36. siz[0][x]+=siz[1][v];
  37. siz[1][x]+=siz[0][v];
  38. f[0][x]+=f[1][v]+edge[i].w*siz[1][v];
  39. f[1][x]+=f[0][v]+edge[i].w*siz[0][v];
  40. }
  41. else
  42. {
  43. siz[0][x]+=siz[0][v];
  44. siz[1][x]+=siz[1][v];
  45. f[0][x]+=f[0][v]+edge[i].w*siz[0][v];
  46. f[1][x]+=f[1][v]+edge[i].w*siz[1][v];
  47. }
  48. }
  49. }
  50. void dfs2(int x,int fa)
  51. {
  52. for(int v,i=head[x];i;i=edge[i].nxt)
  53. {
  54. if((v=edge[i].v)==fa)continue;
  55. if(edge[i].w&1)
  56. {
  57. siz2[0][v]=siz2[1][x];
  58. siz2[1][v]=siz2[0][x];
  59. ans[0][v]=f[0][v]+ans[1][x]-(f[0][v]+edge[i].w*siz[0][v])+edge[i].w*(siz2[1][x]-siz[0][v]);
  60. ans[1][v]=f[1][v]+ans[0][x]-(f[1][v]+edge[i].w*siz[1][v])+edge[i].w*(siz2[0][x]-siz[1][v]);
  61. }
  62. else
  63. {
  64. siz2[0][v]=siz2[0][x];
  65. siz2[1][v]=siz2[1][x];
  66. ans[0][v]=f[0][v]+ans[0][x]-(f[0][v]+edge[i].w*siz[0][v])+edge[i].w*(siz2[0][x]-siz[0][v]);
  67. ans[1][v]=f[1][v]+ans[1][x]-(f[1][v]+edge[i].w*siz[1][v])+edge[i].w*(siz2[1][x]-siz[1][v]);
  68. }
  69. dfs2(v,x);
  70. }
  71. }
  72. int main()
  73. {
  74. freopen("civilization.in","r",stdin);
  75. freopen("civilization.out","w",stdout);
  76. n=read(),q=read();
  77. for(int i=1;i<n;++i)
  78. add(read(),read(),read());
  79. dfs1(1,0);
  80. ans[0][1]=f[0][1];
  81. ans[1][1]=f[1][1];
  82. siz2[0][1]=siz[0][1];
  83. siz2[1][1]=siz[1][1];
  84. dfs2(1,0);
  85. int x;
  86. while(q--)
  87. {
  88. x=read();
  89. printf("%lld %lld\n",ans[1][x],ans[0][x]);
  90. // printf("f %lld %lld\n",f[1][x],f[0][x]);
  91. // printf("siz %d %d\n",siz[1][x],siz[0][x]);
  92. }
  93. fclose(stdin);fclose(stdout);
  94. return 0;
  95. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注