AtCoder Regular Contest 127 题解
sb atcoder 提前比赛时间/fn/fn/fn……sb atcoder 还我 rating/zk/zk/zk
A
签到题,枚举位数 \(+\) 前导 \(1\) 个数然后随便算算贡献即可,时间复杂度 \(\log^2_{10}(n)\)
B
u1s1 这个 B 感觉比一般的 B 难不少啊……
考虑贪心。首先第一位我们随便钦定 \(n\) 个 \(0\),\(n\) 个 \(1\) 和 \(n\) 个 \(2\),那么后面的位我们肯定会贪心地让第一位填 \(2\) 的都填 \(0\),第一位填 \(0/1\) 的自然不用管它们因为我们后面自然有办法为它们填数,但是这样会导致字符串出现重复的情况,怎么解决呢?如果我们发现目前不能区分出来的字符串个数 \(>3^{l-i}\),其中 \(i\) 表示当前填到了第几位,那么我们就贪心地依次填上 \(0000...0,000...1,\cdots,1111...11\),然后把最后的零头放到那“不能被区分出来的字符串集合”中即可。
可能讲得有点玄乎,看代码可能会比较好理解。
const int MAXN=1.5e5;
int n,l,pw3[18];
string s[MAXN+5];
int main(){
scanf("%d%d",&n,&l);
for(int i=(pw3[0]=1);i<=l;i++) pw3[i]=pw3[i-1]*3;
vector<int> id;
for(int i=1;i<=n;i++) id.pb(i);int cur=n;
for(int i=1;i<=n;i++) s[i].pb('0'),s[i+n].pb('1'),s[i+n+n].pb('2');
for(int _=2;_<=l;_++){
cur=id.size();
if(cur<=pw3[l-_]){
for(int x:id) s[x].pb('2'),s[x+n].pb('1'),s[x+n+n].pb('0');
} else if(cur<=pw3[l-_]*2) {
for(int i=0;i<pw3[l-_];i++){
int x=id[i];
// printf("%d\n",x);
s[x].pb('2');s[x+n].pb('1');s[x+n+n].pb('0');
for(int j=0;j<l-_;j++){
s[x].pb('0'+(i/pw3[j]%3));
s[x+n].pb('0'+(i/pw3[j]%3));
s[x+n+n].pb('0'+(i/pw3[j]%3));
}
} vector<int> nw;
for(int i=pw3[l-_];i<id.size();i++){
int x=id[i];
// printf("%d\n",x);
s[x].pb('0');s[x+n].pb('2');s[x+n+n].pb('1');
nw.pb(x);
} id=nw;
} else {
for(int i=0;i<pw3[l-_];i++){
int x=id[i];
s[x].pb('2');s[x+n].pb('1');s[x+n+n].pb('0');
for(int j=0;j<l-_;j++){
s[x].pb('0'+(i/pw3[j]%3));
s[x+n].pb('0'+(i/pw3[j]%3));
s[x+n+n].pb('0'+(i/pw3[j]%3));
}
}
for(int i=pw3[l-_];i<pw3[l-_]*2;i++){
int x=id[i];
s[x].pb('0');s[x+n].pb('2');s[x+n+n].pb('1');
for(int j=0;j<l-_;j++){
s[x].pb('0'+(i/pw3[j]%3));
s[x+n].pb('0'+(i/pw3[j]%3));
s[x+n+n].pb('0'+(i/pw3[j]%3));
}
} vector<int> nw;
for(int i=pw3[l-_]*2;i<id.size();i++){
int x=id[i];
s[x].pb('1');s[x+n].pb('0');s[x+n+n].pb('2');
nw.pb(x);
} id=nw;
}
}
for(int i=1;i<=n*3;i++) cout<<s[i]<<endl;
return 0;
}
C
请问您见过几个 arc C 被评到 2000+
首先考虑一个非常朴素的做法,我们先事先将 \(X\) 减 \(1\),然后每次从高位到低位一位一位考虑,如果当前 \(X\) 等于零那就直接 break
,否则如果当前 \(X\le 2^{n-l}\),其中 \(l\) 为当前考虑的位,那么我们就在这一位上填 \(0\) 并将 \(X\) 减一,否则我们就在这一位上填 \(1\) 并将 \(X\) 减去 \(2^{n-l}\)
然后就是我降智的地方了。由于这题 \(X\) 很大需要高精度,因此我以为直接减 \(1\) 复杂度会退化到平方,于是想着打各种标记之类的奇怪玩意儿,WA 了好几发,事实上直接减 \(1\) 复杂度是正确的,感性理解一下不难发现当你进行一次减 \(1\) 之后退了很多很多位,那么在接下来很长一段时间内就不可能再退这么多位,如果理性证明地大概就 \(\sum\limits_{i=0}^{\log_2(n)}\lfloor\dfrac{n}{2^i}\rfloor=\mathcal O(n)\),因此总时间复杂度也是 \(\mathcal O(n)\)
D
考虑 \(c_i=a_i\oplus b_i\),那么不难发现对于一组 \(i,j\),\(a_i\oplus a_j\) 与 \(b_i\oplus b_j\) 从高到低第一个值不同的位就是 \(c_i\oplus c_j\) 二进制下的 significant bit
,下文中称其为第 \(j\) 位,因此 \(\min(a_i\oplus a_j,b_i\oplus b_j)\) 取到 \(a_i\oplus a_j\) 当且仅当 \(a_i\oplus a_j\) 第 \(d\) 位为 \(1\)。
我们再考虑这样一个问题,给定序列 \(a\) 求它们两两异或和的和,01-trie 是一种方法,事实上我赛时一开始也考虑了这个做法,但是有一种更简单的做法是你考虑每一位的贡献,我们对于每一位记录一下有多少个数这一位为 \(0\),有多少个数这一位为 \(1\),这样可以 \(\mathcal O(1)\) 计算每一位的贡献。
接下来考虑原问题。我们将所有 \(c_i\) 插入 01-trie,然后对于 \(c_i\) 每一个为 \(1\) 的位 \(d\),我们在其对应的 01-trie 的节点上开 4 个长度为 \(\log(n)\) 的数组,下标为 \(j\) 的位置分别维护这样几个信息:对于经过这个节点且 \(c_i\) 为 \(1\) 的 \(i\),有多少个:
- \(a_i\) 第 \(d\) 位为 \(0\) 的 \(i\),满足 \(a_i\) 的第 \(j\) 位为 0/1
- \(a_i\) 第 \(d\) 位为 \(0\) 的 \(i\),满足 \(b_i\) 的第 \(j\) 位为 0/1
- \(a_i\) 第 \(d\) 位为 \(1\) 的 \(i\),满足 \(a_i\) 的第 \(j\) 位为 0/1
- \(a_i\) 第 \(d\) 位为 \(1\) 的 \(i\),满足 \(b_i\) 的第 \(j\) 位为 0/1
这样在遍历 01-trie 计算贡献的过程中,我们考虑计算一个 \(i\) 对答案的贡献时,可以考虑 \(c_i\) 所有为 \(0\) 的位,然后通过预处理的信息在单次 \(\mathcal O(\log n)\) 的时间内计算贡献。
记得加上 \(c_i=c_j\) 的贡献,这一部分的计算是 trivial 的,直接对每一种 \(c_i\) 重复一遍上面弱化版的过程即可。
时间复杂度 \(n\log^2n\)。
const int MAXN=262144;
const int LOG_N=18;
const int MAXP=2097152;
int n,A[MAXN+5],B[MAXN+5],C[MAXN+5];
int ch[MAXP+5][2],cnt[4][MAXP+5][LOG_N+2][2],rt=0,ncnt=0;
vector<int> pc[MAXN+5];
ll res=0;
void insert(int &k,int v,int dep,int a,int b){
if(!k) k=++ncnt;if(!~dep) return;
insert(ch[k][v>>dep&1],v,dep-1,a,b);
if(v>>dep&1){
if(a>>dep&1){
for(int j=0;j<LOG_N;j++) cnt[0][ch[k][v>>dep&1]][j][a>>j&1]++;
for(int j=0;j<LOG_N;j++) cnt[1][ch[k][v>>dep&1]][j][b>>j&1]++;
} else {
for(int j=0;j<LOG_N;j++) cnt[2][ch[k][v>>dep&1]][j][a>>j&1]++;
for(int j=0;j<LOG_N;j++) cnt[3][ch[k][v>>dep&1]][j][b>>j&1]++;
}
}
}
void query(int k,int v,int dep,int a,int b){
if(!k||!~dep) return;
query(ch[k][v>>dep&1],v,dep-1,a,b);
if(~v>>dep&1){
int c=ch[k][~v>>dep&1];
if(!c) return;
// printf("%d %d %d %d %d\n",v,dep,c,a,b);
if(a>>dep&1){
for(int j=0;j<LOG_N;j++) res+=1ll*cnt[0][c][j][~a>>j&1]*(1<<j);
for(int j=0;j<LOG_N;j++) res+=1ll*cnt[3][c][j][~b>>j&1]*(1<<j);
} else {
for(int j=0;j<LOG_N;j++) res+=1ll*cnt[1][c][j][~b>>j&1]*(1<<j);
for(int j=0;j<LOG_N;j++) res+=1ll*cnt[2][c][j][~a>>j&1]*(1<<j);
}
}
}
int cnt0[MAXN+5][LOG_N+2][2];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&A[i]);
for(int i=1;i<=n;i++) scanf("%d",&B[i]),C[i]=A[i]^B[i],pc[C[i]].pb(i);
for(int i=1;i<=n;i++) insert(rt,C[i],LOG_N-1,A[i],B[i]);
for(int i=1;i<=n;i++) for(int j=0;j<LOG_N;j++)
cnt0[C[i]][j][A[i]>>j&1]++;
// for(int i=1;i<=n;i++) printf("%d\n",c[i]);
for(int i=0;i<MAXN;i++){
ll s=0;
for(int id:pc[i]) for(int j=0;j<LOG_N;j++)
s+=1ll*cnt0[i][j][~A[id]>>j&1]*(1<<j);
s>>=1;res+=s;
}
for(int i=1;i<=n;i++) query(rt,C[i],LOG_N-1,A[i],B[i]);
printf("%lld\n",res);
return 0;
}
E
并没有自己想出来,搬运官方题解 ing
首先考虑如果我们想要尽量让大的数都在最终的 \(s\) 中那该怎么选择每次插入的数。显然按 \(1,2,3,\cdots,A\) 的顺序插入肯定是最优的。因此我们假设 \(b_1,b_2,\cdots,b_{A-B}\) 为按 \(1,2,3,\cdots,A\) 顺序插入后剩余的数组成的集合,其中 \(b_i<b_{i+1}\)。
我们再假设 \(c_1,c_2,\cdots,c_{A-B}(c_i<c_{i+1})\) 为按某种顺序插入后剩余的数组成的集合,那么我们不妨猜测 \(c_i\le b_i(i\in[1,A-B])\)。我们假设 \(p_1,p_2,\cdots,p_{B}\) 为按 \(1,2,3,\cdots,A\) 中不在剩余集合中的数组成的集合,\(q_1,q_2,\cdots,q_B\) 为按 \(c_1,c_2,\cdots,c_{A-B}\) 对应的顺序插入后不在剩余集合中的数组成的集合,其中 \(p_i<p_{i+1},q_i<q_{i+1}\),然后对于第 \(i\) 次插入考虑这样构造:
- 如果 \(\exists j,s.t.b_j=i\),那么我们此次插入中插入 \(c_j\),其中 \(b_j=i\)。
- 否则必然 \(\exists j,s.t.p_j=i\),我们就插入 \(q_j\)。
不难证明最后得到的数就是 \(c_1,c_2,\cdots,c_{A-B}\)。因此 \(c_1,c_2,\cdots,c_{A-B}\) 可以作为最终集合存在的充要条件是 \(\forall i\in[1,A-B],c_i\le b_i\)。到这里事情就变得很 trivial 了。\(dp_{i,j}\) 表示考虑了前 \(i\) 个数,\(c_i=j\) 的合法的 \(c\) 的个数,前缀和优化 DP 即可,时间复杂度 \(A^2\)。
AtCoder Regular Contest 127 题解的更多相关文章
- AtCoder Regular Contest 103 题解
C-/\/\/\ #include<algorithm> #include<iostream> #include<cstdlib> #include<ioma ...
- AtCoder Regular Contest 127
Portal B Description 给出\(n(\leq5\times10^4),L(\leq15)\),构造\(3n\)个不同\(L\)位的三进制数,使得在这\(3n\)个数的每一位上,0/1 ...
- Atcoder Regular Contest 123 题解
u1s1 我是真的不知道为什么现场这么多人切了 D,感觉 D 对思维要求显然要高于其他 300+ 人切掉的 D 吧(也有可能是 Atc 用户整体水平提升了?) A 开 幕 雷 击(这题似乎 wjz 交 ...
- AtCoder Regular Contest 094 (ARC094) CDE题解
原文链接http://www.cnblogs.com/zhouzhendong/p/8735114.html $AtCoder\ Regular\ Contest\ 094(ARC094)\ CDE$ ...
- AtCoder Regular Contest 096
AtCoder Regular Contest 096 C - Many Medians 题意: 有A,B两种匹萨和三种购买方案,买一个A,买一个B,买半个A和半个B,花费分别为a,b,c. 求买X个 ...
- AtCoder Regular Contest 061
AtCoder Regular Contest 061 C.Many Formulas 题意 给长度不超过\(10\)且由\(0\)到\(9\)数字组成的串S. 可以在两数字间放\(+\)号. 求所有 ...
- AtCoder Regular Contest 092
AtCoder Regular Contest 092 C - 2D Plane 2N Points 题意: 二维平面上给了\(2N\)个点,其中\(N\)个是\(A\)类点,\(N\)个是\(B\) ...
- AtCoder Regular Contest 093
AtCoder Regular Contest 093 C - Traveling Plan 题意: 给定n个点,求出删去i号点时,按顺序从起点到一号点走到n号点最后回到起点所走的路程是多少. \(n ...
- AtCoder Regular Contest 094
AtCoder Regular Contest 094 C - Same Integers 题意: 给定\(a,b,c\)三个数,可以进行两个操作:1.把一个数+2:2.把任意两个数+1.求最少需要几 ...
随机推荐
- 浅尝装饰器和AOP
[写在前面] 参考文章:https://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html[从简单的例子入手进行讲解,由浅入深,很到位] 装饰器部 ...
- 学习笔记-React的简单介绍&工作原理
一.React简单介绍 1.React起源于Facebook内部项目,与2013年5月 2.是一个用于构建用户界面的JavaScript库 二.React特点 1.声明式设计-React采用声明范式, ...
- 【UE4 C++】 Config Settings配置文件(.ini)
简介 常见存储路径 \Engine\Config\ \Engine\Saved\Config\ (运行后生成) [ProjectName]\Config\ [ProjectName]\Saved\Co ...
- Codeforces Round #750 (Div. 2)
Codeforces Round #750 (Div. 2) A. Luntik and Concerts 思路分析: 首先我们可以肯定的是a,b,c都大于等于1,所以我们先让它们自己抵消自己,最后a ...
- [技术博客] Django中文件的保存与访问
[技术博客] Django中文件的保存与访问 在TextMarking项目开发中,数据库需要保存用户上传的文本文档. 原型设计:用户点击上传文本->保存文本->文本发送到后端保存为文件. ...
- BUAA软件工程个人作业-软件案例分析
BUAA个人博客作业-软件案例分析 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 软件案例分析 我在这个课程的目标是 学习开发软件的能力 这个作 ...
- seata整合多数据源
seata整合多数据源 一.背景 二.整合步骤 1.seata server的搭建 2.引入数据源切换组件 3.引入seata组件 4.配置多数据源 5.关闭seata自己默认的数据源代理 6.配置s ...
- window系统上实现mongodb副本集的搭建
一.问题引出 假设我们生产上的mongodb是单实例在跑,如果此时发生网络发生问题或服务器上的硬盘发生了损坏,那么这个时候我们的mongodb就使用不了.此时我们就需要我们的mongodb实现高可用, ...
- 计算机网络之IPv4(IPv4分组、IPv4地址、NAT、子网划分与子网掩码、CIDR、ARP协议、DHCP、ICMP)
文章转自:https://blog.csdn.net/weixin_43914604/article/details/105138313 学习课程:<2019王道考研计算机网络> 学习目的 ...
- Zabbix 4.4 离线安装 使用mariadb的踩坑,无法停止服务
先分享一个网站,之前就没注意过有这个网站,不知道是啥时候开放的.里面分享了N多zabbix的模板. https://share.zabbix.com/ 报错如下 Unsupported charset ...