A.Parenthesis

括号匹配的问题有一种经典的做法。

将左括号看成1,右括号看成-1,做一遍前缀和sum。

括号序列是合法的当且仅当\(sum[n]=Min(sum[1],sum[2]....sum[n])=0\)时成立。

于是问题变成了交换两个括号后如何维护sum数组的值。

实际上交换a和b之后只会影响到\((sum[a],sum[a+1]....sum[b-1])\)。

1.\(s[a]=(,s[b]=)\) 对应的区间减2。

2.\(s[a]=),s[b]=(\) 对应的区间加2。

我们只需要维护一个支持区间查询最小值,区间加减的数据结构即可。

显然线段树可以完成这些操作。时间复杂度\(O(qlogn)\)

  1. # include <bits/stdc++.h>
  2. using namespace std;
  3. const int N=100005;
  4. int sum[N], seg[N<<3], tag[N<<3];
  5. char s[N];
  6. void push_up(int p){seg[p]=min(seg[p<<1],seg[p<<1|1]);}
  7. void push_down(int p){
  8. if (!tag[p]) return ;
  9. seg[p]+=tag[p]; tag[p<<1]+=tag[p]; tag[p<<1|1]+=tag[p]; tag[p]=0;
  10. }
  11. void init(int p, int l, int r){
  12. if (l<r) {
  13. int mid=(l+r)>>1;
  14. init(p<<1,l,mid); init(p<<1|1,mid+1,r); push_up(p);
  15. }
  16. else seg[p]=sum[l], tag[p]=0;
  17. }
  18. void update(int p, int l, int r, int L, int R, int val){
  19. push_down(p);
  20. if (L>r||R<l) return ;
  21. if (L<=l&&R>=r) tag[p]+=val, push_down(p);
  22. else {
  23. int mid=(l+r)>>1;
  24. update(p<<1,l,mid,L,R,val); update(p<<1|1,mid+1,r,L,R,val); push_up(p);
  25. }
  26. }
  27. int main ()
  28. {
  29. int n, q, l, r;
  30. while (~scanf("%d%d",&n,&q)) {
  31. scanf("%s",s+1);
  32. for (int i=1; i<=n; ++i) sum[i]=sum[i-1]+(s[i]=='('?1:-1);
  33. init(1,1,n);
  34. while (q--) {
  35. scanf("%d%d",&l,&r);
  36. if (l>r) swap(l,r);
  37. if (s[l]!=s[r]) {
  38. if (s[l]=='(') update(1,1,n,l,r-1,-2);
  39. else update(1,1,n,l,r-1,2);
  40. }
  41. puts(seg[1]==0?"Yes":"No");
  42. if (s[l]!=s[r]) {
  43. if (s[l]=='(') update(1,1,n,l,r-1,2);
  44. else update(1,1,n,l,r-1,-2);
  45. }
  46. }
  47. }
  48. return 0;
  49. }

B.权势二进制

题目可以换一种描述。

给出n,问至少可以表示为多少个数位上面只有0和1的数字之和。

显然答案即为n的十进制数位的最大值,即\(max(n\%10,n\%100,n\%1000....)\)

时间复杂度\(O(logn)\)。

  1. # include <bits/stdc++.h>
  2. using namespace std;
  3. char s[10];
  4. int main ()
  5. {
  6. int ans=0;
  7. scanf("%s",s);
  8. for (int i=0; s[i]; ++i) ans=max(ans,s[i]-'0');
  9. printf("%d\n",ans);
  10. return 0;
  11. }

C.天气晴朗的魔法

如果不考虑边权的最大值最小的话,答案就是最大生成树。

现在要求图的生成树中边权的最大值最小。

实际上由Kruskal的算法流程可知,这个值就是图的最小生成树的最大边,不可能比这更小了。

因此,先对图求一遍最小生成树,获得这个最大值,然后把小于等于这个最大值的边

拉出来再求一遍最大生成树,显然即为答案。

时间复杂度\(O(mlogm)\)。

  1. # include <bits/stdc++.h>
  2. using namespace std;
  3. const int N=200005;
  4. struct Edge{int u, v, w;}edge[N];
  5. int n, m, F[N];
  6. long long ans=0;
  7. int find(int x){return F[x]==0?x:F[x]=find(F[x]);}
  8. bool comp(Edge a, Edge b){return a.w<b.w;}
  9. void Kruskal(){
  10. sort(edge+1,edge+m+1,comp);
  11. int Max_w;
  12. for (int i=1; i<=m; ++i) {
  13. int u=find(edge[i].u), v=find(edge[i].v);
  14. if (u==v) continue;
  15. F[u]=v; Max_w=edge[i].w;
  16. }
  17. memset(F,0,sizeof(F));
  18. for (int i=m; i>=1; --i) {
  19. if (edge[i].w>Max_w) continue;
  20. int u=find(edge[i].u), v=find(edge[i].v);
  21. if (u==v) continue;
  22. F[u]=v; ans+=edge[i].w;
  23. }
  24. }
  25. int main ()
  26. {
  27. scanf("%d%d",&n,&m);
  28. for (int i=1; i<=m; ++i) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
  29. Kruskal();
  30. printf("%lld\n",ans);
  31. return 0;
  32. }

D.大鱼吃小鱼

用栈来进行模拟,向右边走的鱼入栈,左边走的鱼和栈顶的鱼进行比较,

如果左边走的鱼比栈顶的鱼体积小,那么就会被吃掉。

否则吃掉栈顶的鱼继续和栈顶的下一个鱼进行比较,直到被吃掉或者栈为空为止。

模拟过程中一共多少鱼会被吃掉,最后拿总数减去它即可答案。

时间复杂度\(O(n)\)。

  1. # include <bits/stdc++.h>
  2. using namespace std;
  3. const int N=100005;
  4. int st[N], top=0;
  5. int main ()
  6. {
  7. int n, a, b, sum=0;
  8. scanf("%d",&n);
  9. for (int i=1; i<=n; ++i) {
  10. scanf("%d%d",&a,&b);
  11. if (b==1) st[++top]=a;
  12. else {
  13. while (top&&st[top]<a) --top, ++sum;
  14. if (top) ++sum;
  15. }
  16. }
  17. printf("%d\n",n-sum);
  18. return 0;
  19. }

E.0和1相等串

将0写成-1,对原序列做一遍前缀和sum。

那么区间\([l,r]\)的0和1出现次数相等的充分必要条件为\(sum[r]=sum[l-1]\)。

现在要找到最大的\(r-l+1\)使得\(sum[r]=sum[l-1]\)。

我们扫一遍sum数组,记录每个val对应的\(sum[i]=val\)的下标i的最大值\(i_{max}\)和最小值\(i_{min}\)。那么这个val对应的答案就是\(i_{max}-i_{min}\)。

对所有val的答案取最大值即可。

时间复杂度\(O(len)\)

  1. # include <bits/stdc++.h>
  2. using namespace std;
  3. const int N=1000005;
  4. int sum[N], Min_p[N<<1], Max_p[N<<1];
  5. char s[N];
  6. const int P=1000000;
  7. int main ()
  8. {
  9. scanf("%s",s+1);
  10. int n=strlen(s+1);
  11. memset(Min_p,-1,sizeof(Min_p)); memset(Max_p,-1,sizeof(Max_p));
  12. for (int i=1; i<=n; ++i) sum[i]=sum[i-1]+(s[i]=='1'?1:-1);
  13. for (int i=0; i<=n; ++i) {
  14. int x=sum[i];
  15. if (Min_p[x+P]==-1) Min_p[x+P]=i;
  16. }
  17. for (int i=n; i>=0; --i) {
  18. int x=sum[i];
  19. if (Max_p[x+P]==-1) Max_p[x+P]=i;
  20. }
  21. int ans=0;
  22. for (int i=0; i<=n+P; ++i) if (Min_p[i]!=-1) ans=max(ans,Max_p[i]-Min_p[i]);
  23. printf("%d\n",ans);
  24. return 0;
  25. }

F.部落划分

如果我们已经确定了最优划分时,最近的两个部落的距离为d,那么我们至多可以将野人划分为几个部落呢?

我们可以推出,如果两个野人之间的距离<d,那么它们必然是一个部落的。

那么我们可以\(O(n^2)\)枚举两个野人,将相同部落的野人的用并查集合并,最后可以得到野人至多被划分为几个部落。

现在的问题是,我们还无法知道答案d应该为多少。

幸运的是,令划分后的部落数\(y=f(d)\),这个函数是单调递减的。

于是我们可以二分d,来找到最大的d,使得\(f(d)=K\)。此时即为答案。

时间复杂度\(O(n^2log(maxdis))\)。

  1. # include <bits/stdc++.h>
  2. using namespace std;
  3. const int N=100005;
  4. int a[N][2], f[N], n, k, F[N];
  5. int find(int x){return F[x]==0?x:F[x]=find(F[x]);}
  6. bool check(double x){
  7. int res=n, u, v;
  8. x=x*x;
  9. memset(F,0,sizeof(F));
  10. for (int i=1; i<=n; ++i) for (int j=i+1; j<=n; ++j) {
  11. if ((a[i][0]-a[j][0])*(a[i][0]-a[j][0])+(a[i][1]-a[j][1])*(a[i][1]-a[j][1])>=x) continue;
  12. u=find(i), v=find(j);
  13. if (u!=v) F[u]=v, --res;
  14. }
  15. return res>=k;
  16. }
  17. int main ()
  18. {
  19. scanf("%d%d",&n,&k);
  20. for (int i=1; i<=n; ++i) scanf("%d%d",&a[i][0],&a[i][1]);
  21. double l=0, r=20000, mid;
  22. for (int i=1; i<=50; ++i) {
  23. mid=(l+r)/2;
  24. if (check(mid)) l=mid;
  25. else r=mid;
  26. }
  27. printf("%.2f\n",mid);
  28. return 0;
  29. }

G.2016

\((a\times b)\%2016=0\Rightarrow ((a\%2016)\times (b\%2016))\%2016=0\)

\(x=a\%2016,y=b\%2016\Rightarrow 0<=x<2016,0<=y<2016\)

预处理出满足条件的\((x,y)\),对于每个这样的\((x,y)\)求出对应的\((a,b)\)有多少种即可。

显然应为\(\frac{n-x}{2016}\times \frac{m-y}{2016}\)。另外注意对x=0和y=0情况的特殊处理即可。

时间复杂度\(O(2016\times 2016)\)。

  1. # include <bits/stdc++.h>
  2. using namespace std;
  3. const int N=2015;
  4. struct Node{int x, y;}node[N*N];
  5. int pos;
  6. void init(){
  7. for (int i=0; i<=2015; ++i) for (int j=0; j<=2015; ++j) {
  8. if (i*j%2016) continue;
  9. node[++pos].x=i; node[pos].y=j;
  10. }
  11. }
  12. int main ()
  13. {
  14. init();
  15. int n, m;
  16. long long ans;
  17. while (~scanf("%d%d",&n,&m)) {
  18. ans=0;
  19. for (int i=1; i<=pos; ++i) {
  20. if (node[i].x>n || node[i].y>m) continue;
  21. ans+=(long long)((n-node[i].x)/2016+(node[i].x?1:0))*((m-node[i].y)/2016+(node[i].y?1:0));
  22. }
  23. printf("%lld\n",ans);
  24. }
  25. return 0;
  26. }

HUAS 2017暑假第六周比赛-题解的更多相关文章

  1. HUAS 2018暑假第一周比赛-题解

    小朋友们有问题评论区 :) B. 子串计算 难度系数 : ☆ Main idea : 模拟 暴力 按照题目的要求一步一步来就行了 之所以可行的原因是从左往右扫,如果扫到一个子串,把它删除掉之后,假设当 ...

  2. CodeForces 569A 第六周比赛C踢

    C - C Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Statu ...

  3. CodeForces 478B 第六周比赛B题

    B - B Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u   Descriptio ...

  4. LightOJ 1317 第六周比赛A题

    A - A Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu   Description Y ...

  5. 暑假集训第一周比赛C题

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=83146#problem/C C - 学 Crawling in process... C ...

  6. 暑假集训第一周比赛G题

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=83146#problem/G G - 向 Crawling in process... C ...

  7. 暑假第六周总结(对HBASE进行编程实践并且安装Redis)

    本周主要是根据教程对HBASE进行了编程实践,对于hadoop的编程来说需要用到很多的.jar 包,在进行编程实践的时候需要参照相关的教程将jar包添加至程序当中去.教程上给的代码还是比较详细的,加上 ...

  8. 大二暑假第六周总结--开始学习Hadoop基础(五)

    简单学习数据仓库HIVE HIVE是一个构建于Hadoop顶端的数据仓库工具 支持大规模数据存储,分析,具有良好的可扩展性 某种程度上可以看做是用户编程接口,本身不存储和处理数据 依赖分布式系统HDF ...

  9. 第六周学习总结-CSS、JavaScript

    2018年8月19日 这是暑假第六周,这一周我把HTML5的标签大致看完了,并且看了一些CSS和JavaScript的内容. 上一周说这周要把那个简陋的网页用CSS修饰一下,但是真正开始做时,才发现C ...

随机推荐

  1. centos7 安装postgres9.4

    1.安装postgres资源:> yum install https://download.postgresql.org/pub/repos/yum/9.4/redhat/rhel-7-x86_ ...

  2. Developing modules for the Apache HTTP Server 2.4

    Developing modules for the Apache HTTP Server 2.4 Available Languages: en This document explains how ...

  3. myBatis逆向工程的使用

    使用myBatis Generator可以快速生成实体类.dao类和mapper文件.有两种方式,现在说的是比较灵活的方式.本文栗子使用的是IDEA,目录结构为maven项目的结构. 1.在pom.x ...

  4. jmeter控制器(一)

    简单控制器: 也就是最简单的控制器,里面没有任何内容的,如下图所示: 当我设置线程为循环10次时,运行简单控制器及下边的注册,设置如下图: 通过查看结果数得知,注册只成功了一次 ,再注册时出现邮箱已存 ...

  5. 【转载】pycharm常用快捷键

    来源: (https://blog.csdn.net/weixin_41059146/article/details/78826163) 1.编辑(Editing) Ctrl + Space    基 ...

  6. 学习python,第四篇:Python 3中bytes/string的区别

    原文:http://eli.thegreenplace.net/2012/01/30/the-bytesstr-dichotomy-in-python-3 python 3中最重要的新特性可能就是将文 ...

  7. docker入门使用教程

    Docker概念 Docker是开发人员和系统管理员 使用容器开发,部署和运行应用程序的平台.使用Linux容器部署应用程序称为容器化.容器不是新的,但它们用于轻松部署应用程序. 容器化越来越受欢迎, ...

  8. jQuery控制a标签不可用

    $('.disableCss').removeAttr('href');//去掉a标签中的href属性 $('.disableCss').removeAttr('onclick');//去掉a标签中的 ...

  9. Daily Scrum 11.18

    今日完成任务: 1.在提问问题的时候为问题创建索引 2.解决了修改个人资料后刷新没有更新的问题 3.初步加入了采纳功能(没完善UI设计) 遇到困难:创建索引之后,跳转到主页,需要重新登录,找了半天不知 ...

  10. C++:new&delete

    一.new的浅析 在C++中,new主要由三种形式:new operator.operator new和placement new • new operator new operator即一些C++书 ...