CF1553D Backspace

题目传送门

题意简述:给定 \(s,t\),现在要依次输入 \(s\) 中的字符。对于每个字符 \(s_i\),你可以选择输入 \(s_i\) 或者使用退格键,判断是否能得到 \(t\)。

不妨将字符串反过来贪心考虑:设 \(i=|s|\),\(p=|t|\)。

  • 如果 \(s_i=t_p\),那么显然选择输入这个字符,\(p\gets p-1\),\(i\gets i-1\)。
  • 否则只能退格,不输入 \(s_i\) 并删除 \(s_{i-1}\),所以 \(i\gets i-2\)。

若 \(p=0\) 则能得到 \(t\),反之则不行。

也许有人会问,如果 \(s_{i-1}\) 也是退格怎么办?实际上若干个连续的退格等价于若干个不连续的退格:不妨设 \(s_{i-1}\) 的退格删了 \(s_j\),而 \(s_i\) 的退格删了 \(s_k\),显然有 \(k<j\)。也就是说 \(s_{k+1}\sim s_{j-1}\) 以及 \(s_{j+1}\sim s_{i-2}\) 全部被删掉了。因此它等价于在 \(s_j\) 处不输入而选择使用退格删除输入的 \(s_k\),在 \(s_i\) 出不输入而选择使用退格删除输入的 \(s_{i-1}\)。若 \(k+1=j\),那么刚好是我们想要的;而如果 \(k,j\) 不连续,那么可以递归证明下去。所以我们可以认为每次退格删除的必定是该位置的前一个字符,贪心算法的正确性就得到了证明。

#include <bits/stdc++.h>
using namespace std; int main(){
int T=1; cin>>T;
while(T--){
string s,t; cin>>s>>t;
int p=t.size()-1;
for(int i=s.size()-1;i>=0;i--)~p&&s[i]==t[p]?p--:i--;
puts(~p?"NO":"YES");
}
return 0;
}

CF1553F Pairwise Modulo

题目传送门

题意简述:给定长度为 \(n\) 的序列 \(a_i\),对于每个 \(k\in [1,n]\),求出 \(\sum_{1\leq i,j\leq k}a_i\bmod a_j\)。

每次考虑新加入的 \(a_i\) 对 \(a_j\ (1\leq j<i)\) 的影响,分成 \(a_i\bmod a_j\) 和 \(a_j\bmod a_i\) 来算。

  • \(a_i\bmod a_j\):

    • 若 \(a_j>a_i\),那么 \(a_j\) 的贡献为 \(a_i\)。
    • 若 \(a_j<a_i\),那么 \(a_j\) 的贡献为 \(a_i-a_j\times \lfloor\dfrac{a_i}{a_j}\rfloor\)。注意到前者与第一种情况的和为 \(a_i\times (i-1)\),而后面一部分可以在计算 \(a_j\) 时枚举 \(c\),对于每个 \([c\times a_j,(c+1)\times a_j-1]\) 区间加 \(c\times a_j\) 预处理出来。
  • \(a_j\bmod a_i\):
    • 若 \(a_j<a_i\),那么 \(a_j\) 的贡献为 \(a_j\)。
    • 若 \(a_j>a_i\),那么 \(a_j\) 的贡献为 \(a_j-a_i\times \lfloor\dfrac{a_j}{a_i}\rfloor\)。注意到前者与第一种情况的和为 \(\sum a_j\),而后面一部分可以枚举 \(c\),对于每个 \([c\times a_i,(c+1)\times a_i-1]\),将答案减去 \(a_j\) 落在该区间的数的个数 \(num\times (c\times a_i)\) 。

因为 \(a_i\) 互不相同,所以我们枚举的区间总数在 \(\sum\dfrac{m}{a_i}\approx m\ln m\)。而 区间加与单点求和 以及 单点加与区间求和 都是 BIT 的拿手好戏,因此总时间复杂度为 \(\mathcal{O}(n\log^2 n)\)。

#include<bits/stdc++.h>
using namespace std; #define ll long long const int N=2e5+5;
const ll M=3e5+5; ll n,sum,res;
struct BIT{
ll c[M];
void add(ll x,ll v){while(x<M)c[x]+=v,x+=x&-x;}
ll query(ll x){ll s=0; while(x)s+=c[x],x-=x&-x; return s;}
}val,num; int main(){
cin>>n;
for(ll i=1,a;i<=n;i++){
cin>>a,res+=sum+a*(i-1)-val.query(a);
for(ll j=a;j<M;j+=a){
int L=min(M-1,j+a-1);
res-=j*(num.query(L)-num.query(j-1));
val.add(j,j),val.add(L+1,-j);
} num.add(a,1),sum+=a,cout<<res<<" ";
}
return 0;
}

CF1553G Common Divisor Graph

题目传送门

题意简述:给出长度为 \(n\) 的序列 \(a_i\),两个点 \(i,j\) 之间有边当且仅当 \((a_i,a_j)>1\)。\(q\) 次询问给定 \(s,t\),你可以选择一个点 \(i\) 并新建节点 \(a_i\times (a_i+1)\),求至少要多少次操作才能使 \(s,t\) 联通。

不算难的一道题,但是赛时没写出来,与 2500+ 失之交臂/流泪。

首先,一个关键的性质是答案不超过 \(2\)。这很显然,因为 \(a_i(a_i+1)\) 一定能被 \(2\) 整除。所以 \((a_s(a_s+1),a_t(a_t+1))>1\)。

于是可以对三种情况分别讨论:

  • 答案为 \(0\):此时 \(s,t\) 在同一个连通块。连通块的预处理很容易:记 \(buc_{a_i}=i\),枚举每个质数 \(p\) 及其倍数 \(cp\),将所有 \(buc_{cp}\) 有值的全部连通即可,可以用并查集实现。
  • 答案为 \(1\):注意到 \(a_i+1\) 所含有的不同质因子是很少的,最多只有 \(7\),并且含有相同质因子的数一定在同一个连通块,这启发我们枚举每个 \(a_i\),求出 “\(a_i\) 所在的连通块” 与 “\(a_i+1\) 所含有的质因子所表示的所有连通块”,并将得到的所有连通块两两标记一下。那么若 \(s,t\) 所处的连通块之间有标记,则答案为 \(1\)。这个可以记录所有标记的连通块对(最多 \(21n\) 个),排序一边后每次询问使用 lower_bound 查找。
  • 否则答案为 \(2\)。

时间复杂度不太会分析,大概是 \(\mathcal{O}(m\log m+d^2n+q\log(d^2n))\),其中 \(m\) 为值域,\(d\) 为不超过值域的数所含有的最多质因子个数,本题中为 \(7\)。实际常数会很小,因为首先有一个 \(\dfrac{1}{2}\) 的常数,同时显然卡不满。

#include <bits/stdc++.h>
using namespace std; #define pii pair <int,int> const int N=1e6+5; int n,q,a[N],buc[N],pr[N];
int f[N],col[N],d[N],c;
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
vector <pii> res; int main(){
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>a[i],f[i]=i,buc[a[i]]=i;
for(int i=2;i<N;i++){
if(pr[i])continue;
for(int j=i,pre=-1;j<N;j+=i){
if(buc[j]){
if(pre==-1)col[i]=find(buc[j]);
else f[find(pre)]=find(buc[j]);
pre=buc[j];
} pr[j]=i;
}
}
for(int i=2;i<N;i++)if(pr[i]==i)col[i]=find(col[i]);
for(int i=1,p=a[1]+1;i<=n;p=a[++i]+1,c=0){
d[++c]=find(i);
while(p>1)d[++c]=col[pr[p]],p/=pr[p];
sort(d+1,d+c+1),c=unique(d+1,d+c+1)-d-1;
for(int i=1;i<c;i++)
for(int j=i+1;j<=c;j++)
res.push_back({d[i],d[j]});
} sort(res.begin(),res.end());
for(int i=1;i<=q;i++){
int x,y; cin>>x>>y,x=find(x),y=find(y);
if(x==y)puts("0");
else{
pii cur={min(x,y),max(x,y)};
auto it=lower_bound(res.begin(),res.end(),cur);
puts(it!=res.end()&&*it==cur?"1":"2");
}
}
return 0;
}

CF1553H XOR and Distance

题目传送门

题意简述:给出 \(n\) 个互不相同的 \(a_i\in [0,2^k)\),对于每个 \(x\in[0,2^k)\),求 \(\min_{i=1}^n\min_{j=i+1}^n|(a_i\oplus x)-(a_j\oplus x)|\)。

看到异或,想到维护一个 01-Trie。

首先考虑 \(x=0\) 的情况:为了查询最近的两个数之间的距离,我们对于每个节点 \(p\),我们首先想到维护落在该节点所表示区间的所有数的最小值和最大值,更新答案的方法显然。

但是,在 \(x\) 的变化过程中,我们需要翻转某一位(不妨设为第 \(i\) 位;位数从左到右从 \(k-1\) 到 \(0\) 标号)的值:由 \(0\) 变为 \(1\) 或者相反。对应到 Trie 上就是交换第 \(k-1-i\) 层所有节点的左右儿子(根节点为第 \(0\) 层)。但是,在交换左右儿子的时候,它们对应的最小值和最大值也会改变,这就意味着我们需要更新左右儿子的整颗子树所存储的信息,四舍五入相当于重构了整棵树:每一层的所有节点的信息都需要更新。这显然是无法承受的。

因此,现在需要一个更加高明的手段,使得交换左右子树时所有子节点信息不变,但仍能推出答案。方法已经呼之欲出了:不妨设节点 \(p\) 所表示的区间为 \([l_p,r_p]\),那么我们仅维护落在该区间的数距离 \(l_p\) 的最小值和最大值即可,即将原来的最小值和最大值减去 \(l_p\)。不难发现,在交换左右子树时,其内部节点的信息完全没有变化。此外,我们还需要记录每个节点所表示的区间长度 \(len_p=r_p-l_p+1\),方便更新信息。通过上述方法,我们可以将翻转第 \(i\) 位的时间复杂度降低到 \(2^{k-i}\)。

但这还是不够,因为 \(x\) 从 \(0\) 枚举到 \(2^k-1\) 的过程中,第 \(i\) 位需要翻转 \(2^{k-i}\) 次,那么第 \(i\) 位的总时间复杂度就是 \(4^{k-i}\),无法承受。可是我们完全不需要这样枚举:将第 \(i\) 位看成第 \(k-i-1\) 位!也就是从 \(0\) 到 \(2^k-1\) 枚举 \(x'\),那么真正的 \(x\) 就是 \(x'\) 在二进制下翻转后的十进制的值。这样一来,我们优化了 \(x\) 的枚举顺序,第 \(i\) 位仅需要翻转 \(2^i\) 次,从而使得第 \(i\) 位的时间复杂度就是 \(2^{k-i}\times 2^i=2^k\)。一共有 \(k\) 位,那么最终的总时间复杂度即为 \(\mathcal{O}(2^k\times k)\)。

#include <bits/stdc++.h>
using namespace std; #define mem(x,v) memset(x,v,sizeof(x)) const int M=1<<21; int n,k,R,node,ls[M],rs[M],mi[M],mx[M],len[M],ans[M],res[M];
void push(int x){
mi[x]=min(mi[ls[x]],mi[rs[x]]+len[x]/2);
mx[x]=max(mx[ls[x]],mx[rs[x]]+len[x]/2);
ans[x]=min(min(ans[ls[x]],ans[rs[x]]),mi[rs[x]]+len[x]/2-mx[ls[x]]);
}
void ins(int val,int bit,int &x){
if(!x)len[x=++node]=1<<bit;
if(!bit)return mi[x]=mx[x]=0,void();
ins(val,bit-1,(val>>bit-1&1)?rs[x]:ls[x]),push(x);
}
void flip(int bit,int cur,int x){
if(cur>bit)flip(bit,cur-1,ls[x]),flip(bit,cur-1,rs[x]),push(x);
else swap(ls[x],rs[x]),push(x); }
int main(){
cin>>n>>k,mem(ans,0x3f),mem(mi,0x3f),mem(mx,0xcf);
for(int i=1,a;i<=n;i++)cin>>a,ins(a,k,R); cout<<ans[R]<<" ";
for(int i=1;i<1<<k;i++){
int id=0;
for(int j=0;j<k;j++){
if((i-1>>k-j-1&1)!=(i>>k-j-1&1))flip(j,k-1,R);
id+=(i>>j&1)<<(k-j-1);
} res[id]=ans[R];
} for(int i=1;i<1<<k;i++)cout<<res[i]<<" ";
return 0;
}

CF1553 部分题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

随机推荐

  1. 数据结构与算法-基础(十一)AVL 树

    AVL 树 是最早时期发明的自平衡二叉搜索树之一.是依据它的两位发明者的名称命名. AVL 树有一个重要的属性,即平衡因子(Balance Factor),平衡因子 == 某个节点的左右子树高度差. ...

  2. 6. 站在巨人的肩膀学习Java Filter型内存马

    本文站在巨人的肩膀学习Java Filter型内存马,文章里面的链接以及图片引用于下面文章,参考文章: <Tomcat 内存马学习(一):Filter型> <tomcat无文件内存w ...

  3. [no_code][Beta] 中期组内总结

    $( "#cnblogs_post_body" ).catalog() 目前scrum meeting beta阶段目前共7次.在alpha阶段我们博客发布时间比较匆忙,是扣分项, ...

  4. Docker制作能够ssh连接的镜像

    本类文章只作为记录使用 命令操作: #拉取Centos 7 docker pull centos:7 #运行一个镜像 docker run -tdi --privileged centos:7 ini ...

  5. Java:final,finally 和 finalize 的区别

    在Java中,final,final和finalize之间有许多差异.final,final和finalize之间的差异列表如下: No final finally finalize 1 final用 ...

  6. 使用ssh连接到centos7中docker容器

    任务: 使用ssh连接到centos7中docker容器 实验步骤: 实验环境搭建,详情请看上一篇. 因为docker中容器的ip通常来说是和真机以及centos7的ip不属于一个网段,因此直接访问是 ...

  7. 使用gitlab runner 进行CI(四):使用Gitlab Page托管项目文档

    目录 1.什么是Gitlab Pages 2.开启Gitlab Pages 3.基本过程 4.托管markdown文档 4.1 安装sphinx等依赖 4.2 配置项目的sphinx配置 4.3 编写 ...

  8. Iceberg概述

    背景 随着大数据领域的不断发展, 越来越多的概念被提出并应用到生产中而数据湖概念就是其中之一, 其概念参照阿里云的简介: 数据湖是一个集中式存储库, 可存储任意规模结构化和非结构化数据, 支持大数据和 ...

  9. 【解决方案】Pyinstaller打包exe策略(简单实用)

    场景说明 在业务场景中, 经常需要Python开发一些小程序/脚本/GUI界面,进行简单的项目测试或未安装Python 的小伙伴们使用. 使用Pyinstaller将Python脚本或者项目打包,生成 ...

  10. Vue的第一课

    终于学习到Vue了,美滋滋,给自己点个赞 前后端作用: 1.1vs1(一个Vue对象控制一个) <body> <div id="app"> <p> ...