果然我还是最菜的==不接受反驳==

Day1

T1:神奇的幻方

思路:直接模拟即可,由于当前放法只与上一放法有关系,用两个变量记录一下即可。10分钟内切掉==

预计得分:100分

实际得分:100分

  1. #include<cstdio>
  2. #include<algorithm>
  3.  
  4. using namespace std;
  5.  
  6. int n,lx,ly;
  7. int vis[][],a[][];
  8.  
  9. int main()
  10. {
  11. freopen("magic.in","r",stdin);
  12. freopen("magic.out","w",stdout);
  13. scanf("%d",&n);
  14. a[][(n+)>>]=;
  15. vis[][(n+)>>]=;
  16. lx=;ly=(n+)>>;
  17. for(int i=;i<=n*n;i++)
  18. {
  19. if(lx==&&ly!=n)
  20. {
  21. a[n][ly+]=i;
  22. vis[n][ly+]=;
  23. lx=n,ly++;
  24. }
  25. else if(lx!=&&ly==n)
  26. {
  27. a[lx-][]=i;
  28. vis[lx-][]=;
  29. lx--;ly=;
  30. }
  31. else if(lx==&&ly==n)
  32. {
  33. a[lx+][ly]=i;
  34. vis[lx+][ly]=;
  35. lx++;
  36. }
  37. else if(lx!=&&ly!=n)
  38. {
  39. if(!vis[lx-][ly+])
  40. {
  41. a[lx-][ly+]=i;
  42. vis[lx-][ly+]=;
  43. lx--;ly++;
  44. }
  45. else
  46. {
  47. a[lx+][ly]=i;
  48. vis[lx+][ly]=i;
  49. lx++;
  50. }
  51. }
  52. }
  53. for(int i=;i<=n;i++)
  54. {
  55. for(int j=;j<=n;j++)
  56. printf("%d ",a[i][j]);
  57. printf("\n");
  58. }
  59. return ;
  60. }

magic

T2:信息传递

思路:方法有多种。可以用tarjan求最小环,或者用拓扑排序,或者用并查集。以前做过,还写了题解 。感觉这是noip第二题少有的简单题了吧。考场上写的tarjan。

预计得分:100分

实际得分:80分

(是这样的qwq 因为实在win下评测的栈小,而且用的cena栈会更小,于是就出锅了qwq,拿到洛咕上是可以满分的,而且这个栈貌似还卡了递归版拓扑排序)

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<stack>
  4. #define maxn 200090
  5.  
  6. using namespace std;
  7.  
  8. int n,r,tot,dfs_clock,scc_cnt,ans=;
  9. int head[maxn],dfn[maxn],low[maxn],size[maxn],scc[maxn];
  10. struct node{
  11. int to,next;
  12. }edge[maxn];
  13. stack<int>s;
  14.  
  15. void add(int x,int y)
  16. {
  17. edge[++tot].to=y;
  18. edge[tot].next=head[x];
  19. head[x]=tot;
  20. }
  21.  
  22. void tarjan(int x)
  23. {
  24. dfn[x]=low[x]=++dfs_clock;
  25. s.push(x);
  26. for(int i=head[x];i;i=edge[i].next)
  27. {
  28. int y=edge[i].to;
  29. if(!dfn[y])
  30. {
  31. tarjan(y);
  32. dfn[x]=min(dfn[x],dfn[y]);
  33. }
  34. else if(!scc[y]) dfn[x]=min(dfn[x],low[y]);
  35. }
  36. if(low[x]==dfn[x])
  37. {
  38. scc_cnt++;
  39. while()
  40. {
  41. int u=s.top();
  42. s.pop();
  43. scc[u]=scc_cnt;
  44. if(x==u) break;
  45. }
  46. }
  47. }
  48.  
  49. int main()
  50. {
  51. freopen("message.in","r",stdin);
  52. freopen("message.out","w",stdout);
  53. scanf("%d",&n);
  54. for(int i=;i<=n;i++)
  55. scanf("%d",&r),add(i,r);
  56. for(int i=;i<=n;i++)
  57. if(!dfn[i]) tarjan(i);
  58. for(int i=;i<=n;i++)
  59. size[scc[i]]++;
  60. for(int i=;i<=scc_cnt;i++)
  61. if(size[i]!=&&size[i]<ans) ans=size[i];
  62. printf("%d",ans);
  63. return ;
  64. }

message

T3:斗地主

思路:我没玩过斗地主qwq,表示看到题理解游戏规则就用了好久。这貌似是个搜索,不过noip还会考裸的搜索嘛qwq(不过真的考了)。平时搜索能力就很弱,独立写出搜索的情况很少,不过最近有意在练习搜索了qwq,也已经有了自己的理解,对搜索应该还是缺乏训练。这篇写了题解(在这里)。考场上写了n=2/3/4的子任务,就是骗分了。

预计得分:30分

实际得分:20分

(是这样的qwq,n==4的情况我应该是写判断的时候出锅了,暴力都打错了。。。)

  1. #include<algorithm>
  2. #include<cstdio>
  3. #include<cstring>
  4.  
  5. using namespace std;
  6.  
  7. int T,n,no,x,ans=;
  8. int tong[];
  9.  
  10. void dfs(int now)
  11. {
  12. int cnt=;
  13. for(int i=;i<=;i++)
  14. {// shunzi single
  15. if(tong[i]) cnt++;
  16. else cnt=;
  17. if(cnt>=)
  18. {
  19. tong[i]--,tong[i-]--,tong[i-]--,tong[i-]--;
  20. int k=i-cnt+;
  21. for(int j=i-;j>=k;j--)
  22. tong[j]--,dfs(now+);
  23. for(int j=k;j<=i;j++)
  24. tong[j]++;
  25. }
  26. }
  27. cnt=;
  28. for(int i=;i<=;i++)
  29. {// shunzi double
  30. if(tong[i]>=) cnt++;
  31. else cnt=;
  32. if(cnt>=)
  33. {
  34. tong[i]-=,tong[i-]-=;
  35. int k=i-cnt+;
  36. for(int j=i-;j>=k;j--)
  37. tong[j]-=,dfs(now+);
  38. for(int j=k;j<=i;j++)
  39. tong[j]+=;
  40. }
  41. }
  42. cnt=;
  43. for(int i=;i<=;i++)
  44. {// shunzi third
  45. if(tong[i]>=) cnt++;
  46. else cnt=;
  47. if(cnt>=)
  48. {
  49. tong[i]-=;
  50. int k=i-cnt+;
  51. for(int j=i-;j>=k;j--)
  52. tong[j]-=,dfs(now+);
  53. for(int j=k;j<=i;j++)
  54. tong[j]+=;
  55. }
  56. }
  57. for(int i=;i<=;i++)
  58. {// four with 2
  59. if(tong[i]>=)
  60. {
  61. tong[i]-=;
  62. for(int j=;j<=;j++)
  63. if(tong[j])
  64. {//2 single
  65. tong[j]--;
  66. for(int k=;k<=;k++)
  67. if(tong[k])
  68. {
  69. tong[k]--;
  70. dfs(now+);
  71. tong[k]++;
  72. }
  73. tong[j]++;
  74. }
  75. for(int j=;j<=;j++)
  76. if(tong[j]>=)
  77. {//2 double
  78. tong[j]-=;
  79. for(int k=;k<=;k++)
  80. if(tong[k]>=)
  81. {
  82. tong[k]-=;
  83. dfs(now+);
  84. tong[k]+=;
  85. }
  86. tong[j]+=;
  87. }
  88. dfs(now+);
  89. //three card
  90. tong[i]+=;
  91. }
  92. }
  93. for(int i=;i<=;i++)
  94. {
  95. if(tong[i]>=)
  96. {
  97. tong[i]-=;
  98. for(int j=;j<=;j++)
  99. if(tong[j])
  100. {//three with 1
  101. tong[j]--;
  102. dfs(now+);
  103. tong[j]++;
  104. }
  105. for(int j=;j<=;j++)
  106. if(tong[j]>=)
  107. {//three with 2
  108. tong[j]-=;
  109. dfs(now+);
  110. tong[j]+=;
  111. }
  112. dfs(now+);// 3 single
  113. tong[i]+=;
  114. }
  115. }
  116. if(tong[]==) now++;
  117. else if(tong[]==) now++;
  118. for(int i=;i<=;i++) if(tong[i]) now+=tong[i]>>;
  119. for(int i=;i<=;i++) if(tong[i]) now+=tong[i]&;
  120. ans=min(ans,now);
  121. }
  122.  
  123. int main()
  124. {
  125. scanf("%d%d",&T,&n);
  126. while(T--)
  127. {
  128. for(int i=;i<=n;i++)
  129. {
  130. scanf("%d%d",&x,&no);
  131. if(x==) x=;
  132. else if(x==) x=;
  133. else if(x==) x=;
  134. tong[x]++;
  135. }
  136. dfs();
  137. printf("%d\n",ans);
  138. ans=;
  139. memset(tong,,sizeof(tong));
  140. }
  141. return ;
  142. }

AC-landlord

Day1 预计得分:230

    实际得分:200

考场上感觉还是有点松懈,第三题没好好想,暴力还写错了,考场上一定要全身心投入啊qwq

Day2

T1:跳石头

思路:裸的二分答案。“最大距离最小”暗示着我们二分的性质,写check函数也很容易,标准的第一题难度。

预计得分:100分

实际得分:100分

(*Add:写的二分的边界细节好像还是不准,还需要多写一些二分题巩固qwq)

  1. #include<cstdio>
  2. #include<algorithm>
  3.  
  4. using namespace std;
  5.  
  6. int lin,n,m;
  7. int seq[];
  8.  
  9. bool check(int x)
  10. {
  11. int pre=,cnt=;
  12. for(int i=;i<=n;i++)
  13. {
  14. if(seq[i]-pre<x) cnt++;
  15. else pre=seq[i];
  16. if(cnt>m) return ;
  17. }
  18. return ;
  19. }
  20.  
  21. int main()
  22. {
  23.  
  24. scanf("%d%d%d",&lin,&n,&m);
  25. for(int i=;i<=n;i++)
  26. scanf("%d",&seq[i]);
  27. seq[n+]=lin;
  28. int l=,r=lin;
  29. while(l<r)
  30. {
  31. int mid=(l+r+)>>;
  32. if(check(mid)) l=mid;
  33. else r=mid-;
  34. }
  35. printf("%d\n",l);
  36. return ;
  37. }

stone

T2:子串

思路:本来dp就弱,字符串也没学多少,二者加起来就mengbier了...读题没有多久就弃疗去看第三题了,结果第三题一打就是几乎三个小时...考前10分钟把k=1的暴力打了,本想苟一苟把k=2的也写上,结果时间也不够了。

预计得分:10分

实际得分:10分

正解:方案数,dp。有经验的dalao可我不是可以轻松推出:设f[i][j][k]表示A串匹配到第i位,B串匹配到第j位,用了k个子串 的方案数。并显然有f[i][j][k]=f[i-1][j-1][k-1]+f[i-1][j-1][k],但是我们冷静分析会发现这个转移是不靠谱的。

首先是它的正确性:上述转移只有在A[i]==B[j]时才成立,于是我们就遗弃掉了没匹配上的情况。

我们可以再开一个辅助转移数组,s[i][j][k]表示一定用到了当前字符A[i]的方案数,f[i][j][k]表示用或不用当前字符的方案数。

分析s数组的转移:转移的前提是A[i]==B[j],既然A[i]一定用上了,那么有独自成一串,和与前面组合成一串的两种情况。

那么有s[i][j][k]=f[i-1][j-1][k-1]+s[i-1][j-1][k]。如果不能转移,则为0.(不能忽视的一步!!后面与滚动数组相关)

再分析f数组的转移:可由使用当前字符和不使用当前字符转移过来.

那么有f[i][j][k]=s[i][j][k]+f[i-1][j][k]。

至此我们成功解决了转移的正确性。

但是显然它是会超空间的,dp的优化我们考虑状态和转移,状态没有可优化的地方,那么我们考虑转移。观察到转移的第一维只与上一值有关,我们就可以用滚动数组。然后我是第一次写滚动数组==,其实就是把第一维改成两个量pre和now,转移后交换pre和now,达到i-1的效果。

以及不要忘记赋初值。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int M=,mod=1e9+;
  5. int n,m,k,dp[][][];
  6. char a[M],b[M];
  7. int main()
  8. {
  9. freopen("substring.in","r",stdin);
  10. freopen("substring.out","w",stdout);
  11. scanf("%d%d%d",&n,&m,&k);
  12. scanf("%s",a+);
  13. scanf("%s",b+);
  14. if(k==)
  15. {
  16. int ans=;
  17. for(int i=;i<=n-m+;i++)
  18. {
  19. bool flag=;
  20. for(int j=;j<=m;j++)
  21. if(a[i+j-]!=b[j]){
  22. flag=;break;
  23. }
  24. if(!flag)ans++;
  25. }
  26. ans%=mod;
  27. printf("%d\n",ans);
  28. return ;
  29. }
  30. else if(k==)
  31. {
  32. int ans=;
  33. for(int i=;i<=n-m+;i++)//枚举第一次选的开始位置
  34. {
  35. for(int len=;len<=m-;len++)//枚举第一次选了几个
  36. {
  37. int len1=m-len;
  38. for(int j=i+len;j<=n-len1+;j++)//枚举第二次从哪儿开始选
  39. {
  40. bool flag=;
  41. int p=;
  42. for(int t=i;t<=i+len-;t++)
  43. {
  44. if(a[t]!=b[++p]){
  45. flag=;break;
  46. }
  47. }
  48. if(flag)continue;
  49. for(int t=j;t<=j+len1-;t++)
  50. {
  51. if(a[t]!=b[++p]){
  52. flag=;break;
  53. }
  54. }
  55. if(!flag){
  56. ans++;
  57. //printf("%d %d %d %d\n",i,i+len-1,j,j+len1-1);
  58. }
  59. }
  60. }
  61. }
  62. cout<<ans<<endl;
  63. return ;
  64. }
  65. else
  66. {
  67. for(int i=;i<=k;i++)
  68. dp[][][i]=;
  69. for(int i=;i<=n;i++)
  70. dp[i][][]=;
  71. for(int i=;i<=m;i++)
  72. dp[][i][]=;
  73. for(int i=;i<=n;i++)
  74. for(int j=;j<=m;j++)
  75. for(int t=;t<=k;t++)
  76. {
  77. if(a[i]==b[j])
  78. dp[i][j][t]=((ll)dp[i][j][t]+dp[i-][j-][t]+dp[i-][j][t-])%mod;
  79. else dp[i][j][t]=((ll)dp[i][j][t]+dp[i-][j][t-])%mod;
  80. printf("%d %d %d %d\n",i,j,t,dp[i][j][t]);
  81. }
  82. cout<<dp[n][m][k]<<endl;
  83. return ;
  84. }
  85.  
  86. }

Chemist的30分做法

  1. #include<cstdio>
  2. #include<algorithm>
  3.  
  4. using namespace std;
  5. typedef long long ll;
  6.  
  7. int n,m,k;
  8. ll moder=1e9+,f[][][],s[][][];
  9. char A[],B[];
  10.  
  11. int main()
  12. {
  13. scanf("%d%d%d",&n,&m,&k);
  14. scanf("%s",A+);
  15. scanf("%s",B+);
  16. int now=,pre=;f[][][]=;
  17. for(int i=;i<=n;i++)
  18. {
  19. f[now][][]=;
  20. for(int j=;j<=m;j++)
  21. for(int q=;q<=k;q++)
  22. {
  23. if(A[i]==B[j]) (s[now][j][q]=s[pre][j-][q]+f[pre][j-][q-])%=moder;
  24. else s[now][j][q]=;
  25. (f[now][j][q]=f[pre][j][q]+s[now][j][q])%=moder;
  26. }
  27. swap(now,pre);
  28. }
  29. printf("%lld",f[pre][m][k]%moder);
  30. return ;
  31. }

substring

T3:运输计划

考场思路:这题我跟它耗了将近三小时qwq.

心路历程如下:(考场上真实记录)

其实感觉m==1的情况还是比较悬的
要是最短路有多条 ,然后最后找到的那条上的最大值恰好比较小 那不就凉了么==

然后到3000的数据,开始想n^2算法应该能想出来,后来感觉好像需要n^2logn
dij的复杂度是多少来着???nlogn?????

如果是nlogn海星 不是就凉了==

dij好像更稳一些,但是我一共也没打过几次dij==

不对,打完dij感觉好像根本不是那么回事 又给删了==
dij求的是单源最短路 复杂度岂不会变成n^3logn???
还不如用floyd呢(滑稽)

那这样好像要用lca了==
LCA复杂度多少来着???

好像想出了正解(??)
但是感觉悬啊
60分差不多吧...

最后当然是非正解了==

预计得分 :0~100分

实际得分 :10分

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cmath>
  4. #include<queue>
  5. #include<vector>
  6.  
  7. using namespace std;
  8. typedef long long ll;
  9.  
  10. int n,m,tot,t,x,y,z,noww,chang;
  11. ll odd,ans;
  12. int head[],cnt[],d[],f[][];
  13. struct node{
  14. int to,val,next;
  15. }edge[];
  16. queue<int>q;
  17. vector<int>son[];
  18.  
  19. void add(int x,int y,int z)
  20. {
  21. edge[++tot].to=y;
  22. edge[tot].next=head[x];
  23. head[x]=tot;
  24. edge[tot].val=z;
  25. }
  26.  
  27. void init()
  28. {
  29. q.push();d[]=;
  30. while(!q.empty())
  31. {
  32. int x=q.front();
  33. q.pop();
  34. for(int i=head[x];i;i=edge[i].next)
  35. {
  36. int y=edge[i].to;
  37. if(d[y]) continue;
  38. d[y]=d[x]+;
  39. f[y][]=x;
  40. for(int j=;j<=t;j++)
  41. f[y][j]=f[f[y][j-]][j-];
  42. q.push(y);
  43. }
  44. }
  45. }
  46.  
  47. int lca(int x,int y)
  48. {
  49. if(d[x]>d[y]) swap(x,y);
  50. for(int i=t;i>=;i--)
  51. if(d[f[y][i]]>=d[x]) y=f[y][i];
  52. if(x==y) return x;
  53. for(int i=t;i>=;i--)
  54. if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
  55. return f[x][];
  56. }
  57.  
  58. bool work(int fa,int x)
  59. {
  60. for(int i=head[fa];i;i=edge[i].next)
  61. if(edge[i].to==x)
  62. {
  63. cnt[i]++;
  64. son[noww].push_back(i);
  65. return ;
  66. }
  67. for(int i=head[fa];i;i=edge[i].next)
  68. {
  69. int y=edge[i].to;
  70. if(y==x)
  71. {
  72. cnt[i]++;
  73. son[noww].push_back(i);
  74. break;
  75. return ;
  76. }
  77. if(work(y,x))
  78. {
  79. cnt[i]++;
  80. son[noww].push_back(i);
  81. return ;
  82. }
  83. }
  84. return ;
  85. }
  86.  
  87. int main()
  88. {
  89. freopen("transport.in","r",stdin);
  90. freopen("transport.out","w",stdout);
  91. scanf("%d%d",&n,&m);
  92. t=log2(n)+;
  93. for(int i=;i<=n-;i++)
  94. {
  95. scanf("%d%d%d",&x,&y,&z);
  96. add(x,y,z),add(y,x,z);
  97. }
  98. init();
  99. for(int i=;i<=m;i++)
  100. {
  101. scanf("%d%d",&x,&y);
  102. noww=i;
  103. int fa=lca(x,y);
  104. if(fa!=x) work(fa,x);
  105. if(fa!=y) work(fa,y);
  106. }
  107. for(int i=;i<=tot;i+=)
  108. cnt[i]=cnt[i]+cnt[i+];
  109. for(int i=;i<=tot;i+=)
  110. {
  111. ll tmp=cnt[i];
  112. tmp*=edge[i].val;
  113. if(tmp>odd) chang=i,odd=tmp;
  114. }
  115. for(int i=;i<=m;i++)
  116. {
  117. ll tmp=;
  118. for(int j=;j<son[i].size();j++)
  119. if(son[i][j]==chang||son[i][j]==chang+) continue;
  120. else tmp+=edge[son[i][j]].val;
  121. ans=max(ans,tmp);
  122. }
  123. printf("%d",ans);
  124. return ;
  125. }

考场代码 10pts

但是后来努力学习了一下60分做法(开始是想搞到 60分的)

60分做法:50pts n² + 10pts m==1,这些方法就是暴力向上跳。

然后暴力的核心思想:因为这是在树上,所以每个点可以认为有唯一的入度,所以可以预处理出到每个点的边的权值,以及这个点的父亲。

瞎搞vis数组开的3000,数组还越界了...导致有两个骗分点一直输出0.

  1. #include<cstdio>
  2. #include<algorithm>
  3. #define maxn 100090
  4.  
  5. using namespace std;
  6. typedef long long ll;
  7.  
  8. int n,m,tot;
  9. int head[maxn],d[maxn],fa[maxn],pre[maxn],vis[][],fin[maxn];
  10. struct node{
  11. int to,next,val;
  12. }edge[*maxn];
  13. struct cellur{
  14. int x,y;
  15. }tas[];
  16.  
  17. ll lmax(ll a,ll b)
  18. {
  19. if(a>b) return a;
  20. else return b;
  21. }
  22.  
  23. void add(int x,int y,int z)
  24. {
  25. edge[++tot].to=y;
  26. edge[tot].next=head[x];
  27. head[x]=tot;
  28. edge[tot].val=z;
  29. }
  30.  
  31. void dfs(int x)
  32. {
  33. d[x]=d[fa[x]]+;
  34. for(int i=head[x];i;i=edge[i].next)
  35. {
  36. int y=edge[i].to;
  37. if(y==fa[x]) continue;
  38. pre[y]=edge[i].val;
  39. fa[y]=x;
  40. dfs(y);
  41. }
  42. }
  43.  
  44. int subw(int pos,int x,int y)
  45. {
  46. int ans=;
  47. if(d[x]<d[y]) swap(x,y);
  48. while(d[x]>d[y])
  49. {
  50. ans+=pre[x];
  51. vis[x][pos]=;
  52. x=fa[x];
  53. }
  54. while(x!=y)
  55. {
  56. ans+=pre[x]+pre[y];
  57. vis[x][pos]=,vis[y][pos]=;
  58. x=fa[x],y=fa[y];
  59. }
  60. return ans;
  61. }
  62.  
  63. void work1()
  64. {
  65. int odd=,ans=;
  66. int x=tas[].x,y=tas[].y;
  67. if(d[x]<d[y]) swap(x,y);
  68. while(d[x]>d[y])
  69. {
  70. ans+=pre[x];
  71. odd=lmax(odd,pre[x]);
  72. x=fa[x];
  73. }
  74. while(x!=y)
  75. {
  76. ans+=pre[x]+pre[y];
  77. odd=lmax(odd,pre[x]);
  78. odd=lmax(odd,pre[y]);
  79. x=fa[x],y=fa[y];
  80. }
  81. printf("%lld",ans-odd);
  82. }
  83.  
  84. void work2()
  85. {
  86. int odd=;
  87. int minn=-;
  88. for(int i=;i<=m;i++) fin[i]=subw(i,tas[i].x,tas[i].y),minn=max(minn,fin[i]);
  89. for(int i=;i<=n;i++)
  90. {
  91. //所有路径只能是pre[i]上的 所以枚举这些边就行
  92. int tmp=;
  93. for(int j=;j<=m;j++)
  94. tmp=max(tmp,fin[j]-pre[i]*vis[i][j]);
  95. //vis数组就是这条边有没有在j这个计划中出现过 只能为0或1
  96. if (minn==-||minn>tmp)minn=tmp;
  97. }
  98. printf("%d",minn);
  99. }
  100.  
  101. int main()
  102. {
  103. scanf("%d%d",&n,&m);
  104. for(int i=;i<=n-;i++)
  105. {
  106. int x=,y=,z=;
  107. scanf("%d%d%d",&x,&y,&z);
  108. add(x,y,z),add(y,x,z);
  109. }
  110. for(int i=;i<=m;i++)
  111. scanf("%d%d",&tas[i].x,&tas[i].y);
  112. fa[]=;
  113. dfs();
  114. if(m==)
  115. work1();
  116. else work2();
  117. return ;
  118. }

努力骗到的60pts

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<algorithm>
  5. using namespace std;
  6. const int M=3e5+,MAX=1e7;
  7. typedef long long ll;
  8. int read()
  9. {
  10. int ans=;
  11. char ch=getchar(),last=' ';
  12. while(ch<''||ch>'')
  13. {last=ch;ch=getchar();}
  14. while(ch>=''&&ch<='')
  15. {ans=ans*+ch-'';ch=getchar();}
  16. if(last=='-')ans=-ans;
  17. return ans;
  18. }
  19. int n,m;
  20. ll d[M],ans=1e12;
  21. int num=,head[M];
  22. struct node{
  23. int beg,end,next,w;
  24. }e[M*];
  25. struct Node{
  26. int str,fin,cost;
  27. }P[M];
  28. struct PLAN{
  29. int from,to;
  30. }p[M];
  31. void add(int x,int y,int z)
  32. {
  33. num++;
  34. e[num].beg=x;
  35. e[num].end=y;
  36. e[num].w=z;
  37. e[num].next=head[x];
  38. head[x]=num;
  39. }
  40.  
  41. int size[M],fa[M],son[M],dep[M];
  42. void dfs1(int x)
  43. {
  44. dep[x]=dep[fa[x]]+;
  45. size[x]=;
  46. for(int i=head[x];i;i=e[i].next)
  47. {
  48. int y=e[i].end;
  49. if(y==fa[x])continue;
  50. fa[y]=x;
  51. d[y]=(ll)d[x]+e[i].w;
  52. dfs1(y);
  53. size[x]+=size[y];
  54. if(!son[x]||size[son[x]]<size[y])
  55. son[x]=y;
  56. }
  57. }
  58.  
  59. int top[M];
  60. void dfs2(int x,int topfa)
  61. {
  62. top[x]=topfa;
  63. if(!son[x])return;
  64. dfs2(son[x],topfa);
  65. for(int i=head[x];i;i=e[i].next)
  66. {
  67. int y=e[i].end;
  68. if(y==son[x]||y==fa[x])continue;
  69. dfs2(y,y);
  70. }
  71. }
  72.  
  73. int LCA(int x,int y)
  74. {
  75. while(top[x]!=top[y])
  76. {
  77. if(dep[top[x]]<dep[top[y]])swap(x,y);
  78. x=fa[top[x]];
  79. }
  80. if(dep[x]>dep[y])swap(x,y);
  81. return x;
  82. }
  83. bool cmp(Node X,Node Y)
  84. {
  85. return X.cost>Y.cost;
  86. }
  87. int main()
  88. {
  89. freopen("transport.in","r",stdin);
  90. freopen("transport.out","w",stdout);
  91. n=read();m=read();
  92. for(int i=;i<=n-;i++)
  93. {
  94. int x=read(),y=read(),z=read();
  95. add(x,y,z);add(y,x,z);
  96. P[i].str=x;P[i].fin=y;P[i].cost=z;
  97. }
  98. for(int i=;i<=m;i++)
  99. p[i].from=read(),p[i].to=read();
  100. dfs1();
  101. dfs2(,);
  102. if((n<=&&m<=)||m==){
  103. //O(nmlogn)枚举暴力,期望得分:55
  104. for(int i=;i<=num;i+=)//枚举改造了哪个航道
  105. {
  106. int x=e[i].beg,y=e[i].end,A;
  107. if(dep[x]<dep[y])A=x;
  108. else A=y;
  109. ll mx=;
  110. for(int j=;j<=m;j++)
  111. {
  112. int B=p[j].from,E=p[j].to;
  113. int lca=LCA(B,E);
  114. ll tim=d[B]+d[E]-*d[lca];
  115. if((LCA(A,B)==A||LCA(A,E)==E)&&dep[lca]<=dep[A])
  116. tim-=e[i].w;
  117. mx=max(mx,tim);
  118. }
  119. ans=min(ans,mx);
  120. }
  121. cout<<ans<<endl;
  122. }
  123. else{
  124. sort(P+,P+n,cmp);
  125. for(int i=;i<=min(n-,(MAX/m));i++)//枚举改造了哪个航道
  126. {
  127. int x=P[i].str,y=P[i].fin,A;
  128. if(dep[x]<dep[y])A=x;
  129. else A=y;
  130. ll mx=;
  131. for(int j=;j<=m;j++)
  132. {
  133. int B=p[j].from,E=p[j].to;
  134. int lca=LCA(B,E);
  135. ll tim=d[B]+d[E]-*d[lca];
  136. if((LCA(A,B)==A||LCA(A,E)==E)&&dep[lca]<=dep[A])
  137. tim-=P[i].cost;
  138. mx=max(mx,tim);
  139. }
  140. ans=min(ans,mx);
  141. }
  142. cout<<ans<<endl;
  143. }
  144. fclose(stdin);fclose(stdout);
  145. return ;
  146. }

Chemist的70pts骗分法

正解:二分答案+lca+树上差分

一句话题意:给你许多树上的链,要求把树上其中一条边变为0后链权值的最大值最小。

这个题出的二分还是十分隐秘的qwq,(比如zhanggenchen篱落疏疏一径深那题)因为题目要我们求计划最大值最小,所以满足二分单调性。

我们就可以二分这个最终的答案。设这个答案为mid,则所有长度>mid的路径上都至少需要删除一条边,对这些路径求交,最优方案是删去路径中长度最大的边。如果删去这条最长边后最长路径还有大于mid的,那么这个答案不合法。

问题的关键转化为求树上路径交,我们可以使用树上差分(现学的)。

另外这里预处理各个计划的链长我用到的是树上倍增求LCA+dfs。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<queue>
  5. #include<cmath>
  6. #define maxn 300090
  7. // long long?
  8. using namespace std;
  9.  
  10. int n,m,t,tot,maxlen,l,r,num,ret;
  11. int pre[maxn],head[maxn],d[maxn],f[maxn][],val[maxn],vis[maxn],dis[maxn];
  12. struct node{
  13. int to,next,val;
  14. }edge[maxn*];
  15. struct cellur{
  16. int x,y,len,lca;
  17. }tas[maxn];
  18.  
  19. void add(int x,int y,int z)
  20. {
  21. edge[++tot].to=y;
  22. edge[tot].next=head[x];
  23. head[x]=tot;
  24. edge[tot].val=z;
  25. }
  26.  
  27. void LCA_prework()
  28. {
  29. queue<int>q;
  30. q.push();d[]=;
  31. while(!q.empty())
  32. {
  33. int u=q.front();q.pop();
  34. for(int i=head[u];i;i=edge[i].next)
  35. {
  36. int v=edge[i].to;
  37. if(d[v]) continue;
  38. d[v]=d[u]+;
  39. f[v][]=u;
  40. pre[v]=edge[i].val;
  41. for(int j=;j<=t;j++)
  42. f[v][j]=f[f[v][j-]][j-];
  43. q.push(v);
  44. }
  45. }
  46. }
  47.  
  48. int LCA(int x,int y)
  49. {
  50. if(d[x]>d[y]) swap(x,y);
  51. for(int i=t;i>=;i--)
  52. if(d[f[y][i]]>=d[x]) y=f[y][i];
  53. if(x==y) return x;
  54. for(int i=t;i>=;i--)
  55. if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
  56. return f[x][];
  57. }
  58.  
  59. void dfs(int x)
  60. {
  61. vis[x]=;
  62. for(int i=head[x];i;i=edge[i].next)
  63. {
  64. int y=edge[i].to;
  65. if(vis[y]) continue;
  66. dis[y]=dis[x]+edge[i].val;
  67. dfs(y);
  68. }
  69. }
  70.  
  71. void review(int u,int fa)
  72. {
  73. for(int i=head[u];i;i=edge[i].next)
  74. {
  75. int v=edge[i].to;
  76. if(v==fa) continue;
  77. review(v,u);
  78. val[u]+=val[v];
  79. }
  80. if(val[u]==num&&pre[u]>ret)
  81. ret=pre[u];//记录路径中最长的边
  82. }
  83.  
  84. bool check(int x)
  85. {
  86. memset(val,,sizeof(val));
  87. num=ret=;
  88. for(int i=;i<=m;i++)
  89. {
  90. if(tas[i].len>x)
  91. {
  92. val[tas[i].x]++;
  93. val[tas[i].y]++;
  94. val[tas[i].lca]-=;
  95. num++;
  96. }
  97. }
  98. review(,);
  99. if(maxlen-ret>x) return ;
  100. return ;
  101. }
  102.  
  103. int main()
  104. {
  105. scanf("%d%d",&n,&m);
  106. t=log2(n)+;
  107. for(int i=;i<=n-;i++)
  108. {
  109. int x=,y=,z=;
  110. scanf("%d%d%d",&x,&y,&z);
  111. add(x,y,z);add(y,x,z);
  112. }
  113. for(int i=;i<=m;i++)
  114. scanf("%d%d",&tas[i].x,&tas[i].y);
  115. LCA_prework();
  116. for(int i=;i<=n;i++)
  117. if(!vis[i]) dfs(i);
  118. for(int i=;i<=m;i++)
  119. {
  120. int fa=LCA(tas[i].x,tas[i].y);
  121. tas[i].lca=fa;
  122. tas[i].len=dis[tas[i].x]+dis[tas[i].y]-*dis[fa];
  123. maxlen=max(maxlen,tas[i].len);
  124. }
  125. r=maxlen;
  126. while(l<r)
  127. {
  128. int mid=(l+r)>>;
  129. if(check(mid)) r=mid;
  130. else l=mid+;
  131. //printf("%d %d\n",ret,num);
  132. }
  133. printf("%d",l);
  134. return ;
  135. }

(但是不开longlong好像也没关系的样子...)

Day2 预计得分:100+10+0~100=110~210

    实际得分:100+10+10=120

感觉考场上不能像我今天一样再孤注一掷写T3正解了吧...,拿个稳妥的暴力分也是好的呀...。所以今天的时间分配出现了很大问题,第二题虽然我dp很不好应该至少还能加上20分k=2的情况吧,实在布星T3把所以m==1的情况都打出来,顺便再打个n==100的情况也比我现在的结果强啊qwq。考试策略和技巧还有待改善。

扯些别的:

现在感觉学习了那么多算法,目的当然是尽量在考场上打出正解。但是事实是,T2正解都很难想全,T3正解就更难了。OI赛制中暴力分,部分分还是王道。学习那么多算法,也是让我们在考场上掌握更多优雅的暴力方法,得到更多的分啊。比如ChemistDay2T3打了一个大概是树剖的东西吧,搞到了60pts(?,而我不会树剖,更不会从树的链角度出发分析==

然后感觉现在基础并不牢固==一些算法掌握的也不牢==比如滚动数组优化当初学长讲了但没写,搜索缺少方法,动规更是一塌糊涂==。对照学长给的noip知识表好像没有多少算法敢说自己掌握的特别牢==,比如树上倍增/差分。

还有一些实用技巧也并不会==,比如生成数据手打就有时候不会,(已加入todolist),有的算法复杂度不确定等等==

NOIp 2015真题模拟赛 By cellur925的更多相关文章

  1. NOIp2017真题模拟赛 By cellur925

    果然我还是最菜的==不接受反驳 (先考了day2喵喵喵) Day2 T1:奶酪 期望得分:100分 实际得分:100分 考察:并查集 思路:这题其实之前做过了==.思路还是比较清晰的,读入时预处理出可 ...

  2. 9-26模拟赛 By cellur925

    1.计数 (count.cpp/c/pas)时间限制:1s内存限制:256MB[问题描述]给出 m 个数 a[1],a[2],…,a[m]求 1~n 中有多少数不是 a[1],a[2],…,a[m]的 ...

  3. 2018.12.30【NOIP提高组】模拟赛C组总结

    2018.12.30[NOIP提高组]模拟赛C组总结 今天成功回归开始做比赛 感觉十分良(zhōng)好(chà). 统计数字(count.pas/c/cpp) 字符串的展开(expand.pas/c ...

  4. NOIP第7场模拟赛题解

    NOIP模拟赛第7场题解: 题解见:http://www.cqoi.net:2012/JudgeOnline/problemset.php?page=13 题号为2221-2224. 1.car 边界 ...

  5. NOIP提高真题整理(2011-2018)-标签

    加粗的后面应该会有相应的简单解析(如果没咕的话:)). 2011 day1 T1:铺地毯:逆着铺 T2:选择客栈:按颜色分类枚举+二分答案 T3:Mayan游戏:大模拟dfs+剪枝 day2 T1:计 ...

  6. 2019.3.16 noiac的原题模拟赛

    RT,这太谔谔了,我不承认这是模拟赛 但是虽然是搬了三道题,题目本身也还能看,就这么着吧 (怎么机房里就我一道原题都没做过啊 T1 CF24D Broken Robot 比较简单地列出式子之后,我们发 ...

  7. [NOIP 2014复习]第三章:动态规划——NOIP历届真题回想

    背包型动态规划 1.Wikioi 1047 邮票面值设计 题目描写叙述 Description 给定一个信封,最多仅仅同意粘贴N张邮票,计算在给定K(N+K≤40)种邮票的情况下(假定全部的邮票数量都 ...

  8. 2015.9.11模拟赛 codevs 4159【hzwer的迷の数列】

    题目描述 Description hzwer找了一个人畜无害的迷の数列…… 现在hzwer希望对这个数列进行一些操作,请你来回答hzwer的问题. 操作一:查询第i个数的大小 操作二:把第i个数的大小 ...

  9. 2017.07.11【NOIP提高组】模拟赛B组

    Summary 今天的比赛打得还不错,第一题被同桌灌输的贪心,纯模拟洗脑了,然后steal的看了一下,发现怎么也对不了,一直在检查.最后10分钟才找出反例,推出动态规划方程,没有想到怎么转移,比赛就结 ...

随机推荐

  1. 【DataStructure】Description and Introduction of Tree

    [Description] At ree is a nonlinear data structure that models a hierarchical organization. The char ...

  2. 【转载】FAT12文件系统之引导扇区结构

    FAT12文件系统之引导扇区结构 文件系统即文件管理系统,是操作系统的重要组成部分之一,如果需要开发底层磁盘驱动或编写自己的操作系统,就必须详细了解文件系统. FAT12是Microsoft公司DOS ...

  3. php利用cookie防止重复提交解决办法

    原理:如果数据通过了上边的两次验证,说明数据是合法有效的数据,这时候我们把提交的数据串接为一个字符串,并用MD5加密后得到一个MD5的值. 接着我们把这个值通过Cookie放进客户端,当用户下一次提交 ...

  4. eclipse无法启动问题记录

    几天没开eclipse,居然报错“can not unload……”,搜索答案发现没有准确的,遵从了一个多人顶赞的办法重下eclipse,把配置文件拷贝一份,结果悲剧了,虽然能够打开了,但我之前配置的 ...

  5. Liunx之Lamp搭建笔记

    1:LAMP源代码搭建用户关系 a.  apache服务以daemon用户的处理请求.以root身份作为主进程. b. php源代码安装,会在httpd.conf文件里自己主动增加调用模块.可是在该文 ...

  6. Codeforces 8VC Venture Cup 2016 - Elimination Round F. Group Projects 差分DP*****

    F. Group Projects   There are n students in a class working on group projects. The students will div ...

  7. [翻译]Unity中的AssetBundle详解(三)

    构建AssetBundles 在AssetBundle工作流程的文档中,我们有一个示例代码,它将三个参数传递给BuildPipeline.BuildAssetBundles函数.让我们更深入地了解我们 ...

  8. design.js

    //模块式开发 var myNamespace = (function () { var myPrivateVar = 0; var myPrivateMethod = function (foo) ...

  9. ES6 一些新特性的总结

    一.箭头函数 ES6中新增了一个箭头函数   ()=>,箭头函数通俗点讲就是匿名函数.箭头函数还有不同点在于改变函数中this,和js中的.bind  的方法差不多,继承后指向的不是最新的函数, ...

  10. linux初级学习笔记五:bash特性详解!(视频序号:03_2,3)

    本节学习的命令:history,alias,ualias,\CMD 本节学习的技能:   bash的特性 光标跳转 查看命令历史 命令历史的使用技巧 给命令起别名 命令替换 文件名通配符 shell: ...