HUAS 2017暑假第六周比赛-题解
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)\)
# include <bits/stdc++.h>
using namespace std;
const int N=100005;
int sum[N], seg[N<<3], tag[N<<3];
char s[N];
void push_up(int p){seg[p]=min(seg[p<<1],seg[p<<1|1]);}
void push_down(int p){
if (!tag[p]) return ;
seg[p]+=tag[p]; tag[p<<1]+=tag[p]; tag[p<<1|1]+=tag[p]; tag[p]=0;
}
void init(int p, int l, int r){
if (l<r) {
int mid=(l+r)>>1;
init(p<<1,l,mid); init(p<<1|1,mid+1,r); push_up(p);
}
else seg[p]=sum[l], tag[p]=0;
}
void update(int p, int l, int r, int L, int R, int val){
push_down(p);
if (L>r||R<l) return ;
if (L<=l&&R>=r) tag[p]+=val, push_down(p);
else {
int mid=(l+r)>>1;
update(p<<1,l,mid,L,R,val); update(p<<1|1,mid+1,r,L,R,val); push_up(p);
}
}
int main ()
{
int n, q, l, r;
while (~scanf("%d%d",&n,&q)) {
scanf("%s",s+1);
for (int i=1; i<=n; ++i) sum[i]=sum[i-1]+(s[i]=='('?1:-1);
init(1,1,n);
while (q--) {
scanf("%d%d",&l,&r);
if (l>r) swap(l,r);
if (s[l]!=s[r]) {
if (s[l]=='(') update(1,1,n,l,r-1,-2);
else update(1,1,n,l,r-1,2);
}
puts(seg[1]==0?"Yes":"No");
if (s[l]!=s[r]) {
if (s[l]=='(') update(1,1,n,l,r-1,2);
else update(1,1,n,l,r-1,-2);
}
}
}
return 0;
}
B.权势二进制
题目可以换一种描述。
给出n,问至少可以表示为多少个数位上面只有0和1的数字之和。
显然答案即为n的十进制数位的最大值,即\(max(n\%10,n\%100,n\%1000....)\)
时间复杂度\(O(logn)\)。
# include <bits/stdc++.h>
using namespace std;
char s[10];
int main ()
{
int ans=0;
scanf("%s",s);
for (int i=0; s[i]; ++i) ans=max(ans,s[i]-'0');
printf("%d\n",ans);
return 0;
}
C.天气晴朗的魔法
如果不考虑边权的最大值最小的话,答案就是最大生成树。
现在要求图的生成树中边权的最大值最小。
实际上由Kruskal的算法流程可知,这个值就是图的最小生成树的最大边,不可能比这更小了。
因此,先对图求一遍最小生成树,获得这个最大值,然后把小于等于这个最大值的边
拉出来再求一遍最大生成树,显然即为答案。
时间复杂度\(O(mlogm)\)。
# include <bits/stdc++.h>
using namespace std;
const int N=200005;
struct Edge{int u, v, w;}edge[N];
int n, m, F[N];
long long ans=0;
int find(int x){return F[x]==0?x:F[x]=find(F[x]);}
bool comp(Edge a, Edge b){return a.w<b.w;}
void Kruskal(){
sort(edge+1,edge+m+1,comp);
int Max_w;
for (int i=1; i<=m; ++i) {
int u=find(edge[i].u), v=find(edge[i].v);
if (u==v) continue;
F[u]=v; Max_w=edge[i].w;
}
memset(F,0,sizeof(F));
for (int i=m; i>=1; --i) {
if (edge[i].w>Max_w) continue;
int u=find(edge[i].u), v=find(edge[i].v);
if (u==v) continue;
F[u]=v; ans+=edge[i].w;
}
}
int main ()
{
scanf("%d%d",&n,&m);
for (int i=1; i<=m; ++i) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
Kruskal();
printf("%lld\n",ans);
return 0;
}
D.大鱼吃小鱼
用栈来进行模拟,向右边走的鱼入栈,左边走的鱼和栈顶的鱼进行比较,
如果左边走的鱼比栈顶的鱼体积小,那么就会被吃掉。
否则吃掉栈顶的鱼继续和栈顶的下一个鱼进行比较,直到被吃掉或者栈为空为止。
模拟过程中一共多少鱼会被吃掉,最后拿总数减去它即可答案。
时间复杂度\(O(n)\)。
# include <bits/stdc++.h>
using namespace std;
const int N=100005;
int st[N], top=0;
int main ()
{
int n, a, b, sum=0;
scanf("%d",&n);
for (int i=1; i<=n; ++i) {
scanf("%d%d",&a,&b);
if (b==1) st[++top]=a;
else {
while (top&&st[top]<a) --top, ++sum;
if (top) ++sum;
}
}
printf("%d\n",n-sum);
return 0;
}
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)\)
# include <bits/stdc++.h>
using namespace std;
const int N=1000005;
int sum[N], Min_p[N<<1], Max_p[N<<1];
char s[N];
const int P=1000000;
int main ()
{
scanf("%s",s+1);
int n=strlen(s+1);
memset(Min_p,-1,sizeof(Min_p)); memset(Max_p,-1,sizeof(Max_p));
for (int i=1; i<=n; ++i) sum[i]=sum[i-1]+(s[i]=='1'?1:-1);
for (int i=0; i<=n; ++i) {
int x=sum[i];
if (Min_p[x+P]==-1) Min_p[x+P]=i;
}
for (int i=n; i>=0; --i) {
int x=sum[i];
if (Max_p[x+P]==-1) Max_p[x+P]=i;
}
int ans=0;
for (int i=0; i<=n+P; ++i) if (Min_p[i]!=-1) ans=max(ans,Max_p[i]-Min_p[i]);
printf("%d\n",ans);
return 0;
}
F.部落划分
如果我们已经确定了最优划分时,最近的两个部落的距离为d,那么我们至多可以将野人划分为几个部落呢?
我们可以推出,如果两个野人之间的距离<d,那么它们必然是一个部落的。
那么我们可以\(O(n^2)\)枚举两个野人,将相同部落的野人的用并查集合并,最后可以得到野人至多被划分为几个部落。
现在的问题是,我们还无法知道答案d应该为多少。
幸运的是,令划分后的部落数\(y=f(d)\),这个函数是单调递减的。
于是我们可以二分d,来找到最大的d,使得\(f(d)=K\)。此时即为答案。
时间复杂度\(O(n^2log(maxdis))\)。
# include <bits/stdc++.h>
using namespace std;
const int N=100005;
int a[N][2], f[N], n, k, F[N];
int find(int x){return F[x]==0?x:F[x]=find(F[x]);}
bool check(double x){
int res=n, u, v;
x=x*x;
memset(F,0,sizeof(F));
for (int i=1; i<=n; ++i) for (int j=i+1; j<=n; ++j) {
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;
u=find(i), v=find(j);
if (u!=v) F[u]=v, --res;
}
return res>=k;
}
int main ()
{
scanf("%d%d",&n,&k);
for (int i=1; i<=n; ++i) scanf("%d%d",&a[i][0],&a[i][1]);
double l=0, r=20000, mid;
for (int i=1; i<=50; ++i) {
mid=(l+r)/2;
if (check(mid)) l=mid;
else r=mid;
}
printf("%.2f\n",mid);
return 0;
}
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)\)。
# include <bits/stdc++.h>
using namespace std;
const int N=2015;
struct Node{int x, y;}node[N*N];
int pos;
void init(){
for (int i=0; i<=2015; ++i) for (int j=0; j<=2015; ++j) {
if (i*j%2016) continue;
node[++pos].x=i; node[pos].y=j;
}
}
int main ()
{
init();
int n, m;
long long ans;
while (~scanf("%d%d",&n,&m)) {
ans=0;
for (int i=1; i<=pos; ++i) {
if (node[i].x>n || node[i].y>m) continue;
ans+=(long long)((n-node[i].x)/2016+(node[i].x?1:0))*((m-node[i].y)/2016+(node[i].y?1:0));
}
printf("%lld\n",ans);
}
return 0;
}
HUAS 2017暑假第六周比赛-题解的更多相关文章
- HUAS 2018暑假第一周比赛-题解
小朋友们有问题评论区 :) B. 子串计算 难度系数 : ☆ Main idea : 模拟 暴力 按照题目的要求一步一步来就行了 之所以可行的原因是从左往右扫,如果扫到一个子串,把它删除掉之后,假设当 ...
- CodeForces 569A 第六周比赛C踢
C - C Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Submit Statu ...
- CodeForces 478B 第六周比赛B题
B - B Time Limit:1000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Descriptio ...
- LightOJ 1317 第六周比赛A题
A - A Time Limit:2000MS Memory Limit:32768KB 64bit IO Format:%lld & %llu Description Y ...
- 暑假集训第一周比赛C题
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=83146#problem/C C - 学 Crawling in process... C ...
- 暑假集训第一周比赛G题
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=83146#problem/G G - 向 Crawling in process... C ...
- 暑假第六周总结(对HBASE进行编程实践并且安装Redis)
本周主要是根据教程对HBASE进行了编程实践,对于hadoop的编程来说需要用到很多的.jar 包,在进行编程实践的时候需要参照相关的教程将jar包添加至程序当中去.教程上给的代码还是比较详细的,加上 ...
- 大二暑假第六周总结--开始学习Hadoop基础(五)
简单学习数据仓库HIVE HIVE是一个构建于Hadoop顶端的数据仓库工具 支持大规模数据存储,分析,具有良好的可扩展性 某种程度上可以看做是用户编程接口,本身不存储和处理数据 依赖分布式系统HDF ...
- 第六周学习总结-CSS、JavaScript
2018年8月19日 这是暑假第六周,这一周我把HTML5的标签大致看完了,并且看了一些CSS和JavaScript的内容. 上一周说这周要把那个简陋的网页用CSS修饰一下,但是真正开始做时,才发现C ...
随机推荐
- 我用 Python 爬取微信好友,最后发现一个大秘密
前言 你身处的环境是什么样,你就会成为什么样的人.现在人们日常生活基本上离不开微信,但微信不单单是一个即时通讯软件,微信更像是虚拟的现实世界.你所处的朋友圈是怎么样,慢慢你的思想也会变的怎么样.最近在 ...
- VBA_话费明细单_格式调整
VBA-联通话费明细单-格式调整 Sub ChangeColumn() Rows(1).RowHeight = 24 '设置第1行的行高 Rows(1).WrapText = True '设置第1行的 ...
- 将exe依赖运行的dll,合并入exe中,整个程序仅存在一个exe文件
方法一: 使用ILMerge合并winform生成的exe和引用的dll文件 参考:https://blog.csdn.net/u010108836/article/details/76782375 ...
- JUC——并发集合类
如果要进行多个数据的保存,无疑首选类集(List.Set.Queue.Map),在类集的学习的时候也知道一个概念:许多集合的子类都具有同步与异步的差别,但是如果真的要在多线程之中去使用这些类,是否真的 ...
- 从一个简单的寻路问题深入Q-learning
这第一篇随笔实际上在我的科学网博客上是首发,我重新拿到博客园再发一次是希望以此作为我学习Q-learning的一个新的开始.以后这边主技术,科学网博客主理论.我也会将科学网那边技术类的文章转过来的.希 ...
- Hyperledger Fabric 中channel配置相关数据结构
channel Configuration Transaction Hyperledger Fabric区块链网络中的配置存储在一个configuration-transaction的集合中,每个ch ...
- Spring Data REST PATCH请求远程代码执行漏洞(CVE-2017-8046) 本地复现方法
#1背景 Spring Data REST是Spring Data项目的一部分,可以轻松地在Spring Data存储库之上构建超媒体驱动的REST Web服务. 恶意的PATCH请求使用精心构造 ...
- Java时间格式的使用,bug难时真是坑
很简单的问题,尤其是新手开发,要多自己动手写代码,都说程序猿大都是程序的搬用工,其实不然,好的写手,和差的写手,区别就在是不是会花时间读读代码,并且自己动手实践一下,其实一个程序范这样的错误,绝对是低 ...
- Performance — 前端性能监控利器
Performance是一个做前端性能监控离不开的API,最好在页面完全加载完成之后再使用,因为很多值必须在页面完全加载之后才能得到.最简单的办法是在window.onload事件中读取各种数据. 大 ...
- 随手记录-linux-Linux目录结构
转:别人的 装完Linux,首先需要弄清Linux 标准目录结构 / root —?启动Linux时使用的一些核心文件.如操作系统内核.引导程序Grub等. home —?存储普通用户的个人文件 ft ...