[关闭]
@dxbdly 2020-12-20T07:00:59.000000Z 字数 4617 阅读 172

C2020 2020.10.3测试

信息学——模拟赛


考试情况

考场上期望得分VS实际得分:

期望得分:

T1 T2 T3 总分
100 100 100 300

实际得分:

T1 T2 T3 总分
40 100 50 190

……(

T1 file

分析

模拟题,模拟Trie树或直接画树模拟即可。

注意,不同文件目录下可能有相同的文件名,所以不能用map建树直接模拟。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int n;
  4. int tot;
  5. char s[10005][1005];
  6. string id[10005];
  7. int edge[10005][1005];
  8. bool vst[10005];
  9. map <string,int> mapp;
  10. inline bool cmp(int x,int y)
  11. {
  12. return id[x]<id[y];
  13. }
  14. inline void search(int x,int dep)
  15. {
  16. vst[x]=1;
  17. cout<<id[x]<<endl;
  18. sort(edge[x]+1,edge[x]+edge[x][0]+1,cmp);
  19. for (register int i=1;i<=edge[x][0];++i)
  20. if (!vst[edge[x][i]])
  21. {
  22. for (register int j=1;j<=dep;++j)
  23. printf("| ");
  24. printf("|----");
  25. search(edge[x][i],dep+1);
  26. }
  27. }
  28. int main(){
  29. freopen("file.in","r",stdin);
  30. freopen("file.out","w",stdout);
  31. scanf("%d",&n);
  32. for(register int i=1;i<=n;++i)
  33. {
  34. scanf("%s",s[i]);
  35. int len=strlen(s[i]),pre_x=0;
  36. string c="",pre="";
  37. for (register int j=0;j<=len;pre+=s[i][j],++j)
  38. {
  39. if (s[i][j]=='/'||j==len)
  40. {
  41. int &x=mapp[pre];
  42. if (!x)
  43. x=(++tot),id[x]=c;
  44. edge[pre_x][++edge[pre_x][0]]=x;
  45. pre_x=x;
  46. c="";
  47. }
  48. else
  49. c+=s[i][j];
  50. }
  51. }
  52. search(1,0);
  53. return 0;
  54. }

总结与反思

题面上没写的就是有可能!!!

T2 compile

分析

乍一看感觉是DP,但是发现DP无论怎样都只能做到,根据数据范围考虑贪心。

一个显然的贪心策略:每次取当前可取的最大数。但显然是错的。

  1. hack数据:
  2. 4 2
  3. 9 8 1 8
  4. 贪心解:9+1=10
  5. 正解:8+8=16

问题就出在取了这点就不能取相邻点上,这样也许会漏失最优解。

这时候就有一个sao操作——反悔贪心。

其实反悔贪心就是当我们发现当前的最优解不是全局最优解时,撤销当前操作并执行正确操作。

显然所有贪心都可以做这样的反悔操作,只不过有些贪心反悔之后复杂度太高或是找不到如何执行正确操作。

此题是通过巧妙地计算差值来反悔。

假设我们现在取出的最优解(拿一个堆维护最大值)为,前继为,后继为

则我们想要反悔,也就是撤销取的操作,改为取

那么我们考虑在堆中插入一个值为的点,这样当我们把这个点取出就达到了撤销的贡献加上的贡献的操作。

这样连续操作次就得到了答案。

  1. #include<bits/stdc++.h>
  2. #define mp make_pair
  3. using namespace std;
  4. inline int read()
  5. {
  6. int x=0;
  7. char c=getchar();
  8. bool f=0;
  9. while (!isdigit(c))
  10. f|=(c=='-'),c=getchar();
  11. while (isdigit(c))
  12. x=(x<<3)+(x<<1)+(c^48),c=getchar();
  13. return f?-x:x;
  14. }
  15. int n,m,ans;
  16. int a[200005];
  17. struct node{
  18. int pre,nex;
  19. int flag;
  20. }edge[200005];
  21. priority_queue < pair<int,int> > q;
  22. inline void update(int x)
  23. {
  24. edge[edge[x].nex].flag=1,edge[edge[edge[x].nex].nex].pre=x,edge[x].nex=edge[edge[x].nex].nex;
  25. edge[edge[x].pre].flag=1,edge[edge[edge[x].pre].pre].nex=x,edge[x].pre=edge[edge[x].pre].pre;
  26. }
  27. int main(){
  28. freopen("compile.in","r",stdin);
  29. freopen("compile.out","w",stdout);
  30. n=read(),m=read();
  31. if (m>n/2)
  32. {
  33. printf("Error!");
  34. return 0;
  35. }
  36. for (register int i=1;i<=n;++i)
  37. a[i]=read(),q.push(mp(a[i],i));
  38. edge[1].pre=n,edge[1].nex=2,edge[n].pre=n-1,edge[n].nex=1;
  39. for (register int i=2;i<n;++i)
  40. edge[i].pre=i-1,edge[i].nex=i+1;
  41. for (register int i=1;i<=m;++i)
  42. {
  43. int x;
  44. while (edge[(x=q.top().second)].flag)
  45. q.pop();
  46. ans+=q.top().first;
  47. q.pop(),a[x]=a[edge[x].pre]+a[edge[x].nex]-a[x],q.push(mp(a[x],x));
  48. update(x);
  49. }
  50. printf("%d",ans);
  51. return 0;
  52. }

总结与反思

带反悔的贪心一般分为反悔自动机和反悔堆,比较少见,但是似乎可以当做骗分技巧。

T3 cost

分析

MST+LCA的经典套路题(可见luogu货车运输),这种题一般都会推出除MST上的边有用,其他边一定都不是最优解的边这种结论。

例如此题,费用为所有经过路径的最小值,而只要此图联通,那些较大的边一定不会被走(很显然吧不证明了)

而最小生成树就满足边最小且联通,所以我们先跑一遍MST,将图变成树,则在树上求距离就是LCA了。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. inline int read()
  4. {
  5. int x=0;
  6. char c=getchar();
  7. bool f=0;
  8. while (!isdigit(c))
  9. f|=(c=='-'),c=getchar();
  10. while (isdigit(c))
  11. x=(x<<3)+(x<<1)+(c^48),c=getchar();
  12. return f?-x:x;
  13. }
  14. int n,m,q;
  15. int father[100005];
  16. struct Line{
  17. int u,v,w;
  18. }line[200005];
  19. struct node{
  20. int v,nex;
  21. int w;
  22. }edge[200005];
  23. int head[100005],len,tot;
  24. int dep[100005],f[100005][25],maxx[100005][25];
  25. inline bool operator <(Line x,Line y)
  26. {
  27. return x.w<y.w;
  28. }
  29. inline void add(int u,int v,int w)
  30. {
  31. tot++,line[tot].u=u,line[tot].v=v,line[tot].w=w;
  32. }
  33. inline void make_map(int u,int v,int w)
  34. {
  35. len++;
  36. edge[len].nex=head[u];
  37. edge[len].v=v;
  38. edge[len].w=w;
  39. head[u]=len;
  40. }
  41. inline int Find(int x)
  42. {
  43. if (father[x]!=x)
  44. return father[x]=Find(father[x]);
  45. return father[x];
  46. }
  47. inline void unnion(int f1,int f2)
  48. {
  49. father[f2]=f1;
  50. }
  51. inline void get_MST()
  52. {
  53. tot=0;
  54. for (register int i=1;i<=m;++i)
  55. {
  56. int u=line[i].u,v=line[i].v,w=line[i].w,f1=Find(u),f2=Find(v);
  57. if (f1!=f2)
  58. {
  59. tot++,unnion(f1,f2);
  60. make_map(u,v,w),make_map(v,u,w);
  61. if (tot==n-1)
  62. break;
  63. }
  64. }
  65. }
  66. inline void Deal_First(int x,int fa)
  67. {
  68. dep[x]=dep[fa]+1;
  69. for (register int i=1;i<=20;++i)
  70. f[x][i]=f[f[x][i-1]][i-1],maxx[x][i]=max(maxx[x][i-1],maxx[f[x][i-1]][i-1]);
  71. for (register int i=head[x];i;i=edge[i].nex)
  72. {
  73. int y=edge[i].v,z=edge[i].w;
  74. if (y==fa)
  75. continue;
  76. f[y][0]=x,maxx[y][0]=z;
  77. Deal_First(y,x);
  78. }
  79. }
  80. inline int get_LCA(int x,int y)
  81. {
  82. int ans=0;
  83. if (dep[x]<dep[y])
  84. swap(x,y);
  85. for (register int i=20;i>=0;--i)
  86. {
  87. if (dep[f[x][i]]>=dep[y])
  88. ans=max(ans,maxx[x][i]),x=f[x][i];
  89. if (x==y)
  90. return ans;
  91. }
  92. for (register int i=20;i>=0;--i)
  93. if (f[x][i]!=f[y][i])
  94. ans=max(ans,max(maxx[x][i],maxx[y][i])),x=f[x][i],y=f[y][i];
  95. return max(ans,max(maxx[x][0],maxx[y][0]));
  96. }
  97. int main(){
  98. freopen("cost.in","r",stdin);
  99. freopen("cost.out","w",stdout);
  100. n=read(),m=read();
  101. for (register int i=1;i<=n;++i)
  102. father[i]=i;
  103. for (register int i=1;i<=m;++i)
  104. {
  105. int u=read(),v=read(),w=read();
  106. add(u,v,w);
  107. }
  108. sort(line+1,line+m+1);
  109. get_MST(),Deal_First(1,0);
  110. q=read();
  111. while (q--)
  112. {
  113. int u=read(),v=read();
  114. printf("%d\n",get_LCA(u,v));
  115. }
  116. return 0;
  117. }

总结与反思

经典套路,考场上LCA写挂了……

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