2020-04-15 23:24阅读: 284评论: 0推荐: 0

Codeforces Round #633 (Div. 1)

A. Powered Addition (CF 1338 A)

题目大意

给定一个n个数字的数组a,对于每一个正整数x,你可以选择若干个数字i1,i2,i3,...,ik,使得aij=aij+2x1, 1jk。当然你也可以不进行选择。求最小的数字T,使得当x取过了1~T进行操作后,数组a是一个非递减数组。

解题思路

从左到右,如果ai>ai+1,我们就把ai+1变成ai,并记录最大的aiai+1,最大值在二进制下的位数即是答案。

操作就很简单,差值在二进制下第i位是1就在x=i的时候选择那个数就好了。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int main(void) {
int kase; read(kase);
for (int ii = 1; ii <= kase; ++ii) {
int n;
read(n);
int ans=0;
int qwq=-1e9-7;;
for(int u,i=1;i<=n;++i){
read(u);
if (qwq<=u) qwq=u;
else{
ans=max(ans,qwq-u);
}
}
int cnt=0;
while(ans){
ans>>=1;
++cnt;
}
write(cnt,'\n');
}
return 0;
}


B. Edge Weight Assignment (CF 1338 B)

题目大意

给定一棵无权树,要求对边赋一个正权值,使得任意两个叶子节点之间的路径权值异或和为0。求所赋的不同权值数的最小值和最大值。

解题思路

如果任意两个叶子节点之间的路径长度是偶数,那么我们对全部边赋1即可,最小为1

如果存在奇数长度的,注意到123=0。我们把不与叶子节点相连的边赋为1,是奇数长度的那对叶子节点a,b相连的边,一个赋2,一个赋3,那其他叶子节点对于这两个叶子节点,如果是偶数路径,则与其叶子节点相连的边的权值一样,奇数路径则相反(2332)。

对于不是a,b的一对点c,d,它们的边权异或和(c,d)一定为0,因为边权异或和可以拆成(c,d)=(c,a)(a,d),因为c,dlcaa的边权异或了两次抵消掉了。而在前面的构造里我们知道(c,a)=0,(a,d)=0,所以(c,d)=0。也即最小为3

判断奇数长度的,从一个叶子节点搜(初始深度为1)发现有深度是偶数深度的叶子节点即可得知有奇数长度。

至于最大的,我们可以设想,除了叶子节点相连的边,其他的边都填不同的数,然后选择一个叶子节点a,其边也填一个不同的数,然后对于其他叶子节点b,其边填(a,fa[b])的值(fa[b]表示与叶子节点相连的边的另外一个节点)。对于不是叶子节点a的点b,c,其(b,c)也一定为0,证明也如同上面的方法,将(b,c)=(b,a)(a,c)

由于可以填的数无穷大,我们可以证明 (猜想) 这一定可以做到的。

所以,只有那些一个节点连了多个叶子节点的那些边的权值一定相等外,其他的都可以不一样。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
void DFS(int u,int fa,int deep[],vector<int> edge[]){
deep[u]=deep[fa]+1;
for(auto v:edge[u]){
if (v==fa) continue;
DFS(v,u,deep,edge);
}
}
int dfs(int u,int fa,bool &qwq,int &ans,int deep[],vector<int> edge[],int st){
int cnt=0;
int aa=0;
deep[u]=deep[fa]+1;
for(auto v:edge[u]){
if (v==fa) continue;
++cnt;
aa+=dfs(v,u,qwq,ans,deep,edge,st);
}
if (!cnt){
if (!(deep[u]&1)) qwq=true;
return 1;
}
if (fa==st) ++aa;
ans-=max(0,aa-1);
return 0;
}
int main(void) {
int n;
read(n);
vector<int> edge[n+1];
for(int u,v,i=1;i<n;++i){
read(u);
read(v);
edge[u].push_back(v);
edge[v].push_back(u);
}
int deep[n+1]={0};
DFS(1,1,deep,edge);
int st=0,dest=0;
for(int i=1;i<=n;++i)
if (dest<deep[i]){
dest=deep[i];
st=i;
}
deep[st]=0;
bool qwq=false;
int ans=n-1;
dfs(st,st,qwq,ans,deep,edge,st);
printf("%d %d\n",(qwq?3:1),ans);
return 0;
}


C. Perfect Triples (CF 1338 C)

题目大意

有一个有无穷无尽个正整数的数组s,其构造方法如下:

  • a<b<c
  • a,b,cs
  • abc=0
  • (a,b,c)是可选中的字典序最小的一组
  • 把a,b,c依次加入s数组的末尾
  • 重复第一步

现有t组询问,每组询问一个数n,问你数组中第n个数(从1开始)是多少。

解题思路

打表大法好

注意到123=0

这恰好是4进制。于是我们可以把数转成四进制(二进制下俩俩合并),三个数看成一组,对于这一组的数,四进制下每一位我们就可以单独考虑。

对于最高位,由于a<b<c,所以最高位上一定是123

然后对于以下的每一位,只有四种情况:

  • 0 0 0
  • 1 2 3
  • 2 3 1
  • 3 1 2

这四种情况也是按照字典序从小到大排好的,其余的情况会出现重复数字。

按照字典序从小到大构造的三元组的方法就很明显啦,对于三个数的每一位,依次取遍四种情况,然后到下一位。

这也才造成我们打的表里面,第一个数以4n个分组的结果。

给定n就相当于问第n13组(从0开始)的第(n1)%3位是多少。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
void work(LL id,LL i,pair<LL,LL> &ans){
if (i<0) return;
if (i==0) {
LL rank=id;
if (rank==1){
ans.first^=(1ll<<(i));
ans.second^=(1ll<<(i+1));
}else if (rank==2){
ans.first^=(1ll<<(i+1));
ans.second^=((1ll<<(i))^(1ll<<(i+1)));
}else if (rank==3){
ans.first^=((1ll<<(i))^(1ll<<(i+1)));
ans.second^=(1ll<<(i));
}
return;
}
LL cnt=(1ll<<(i));
work(id%cnt,i-2,ans);
LL rank=id/cnt;
if (rank==1){
ans.first^=(1ll<<(i));
ans.second^=(1ll<<(i+1));
}else if (rank==2){
ans.first^=(1ll<<(i+1));
ans.second^=((1ll<<(i))^(1ll<<(i+1)));
}else if (rank==3){
ans.first^=((1ll<<(i))^(1ll<<(i+1)));
ans.second^=(1ll<<(i));
}
}
int main(void) {
int t;
read(t);
while(t--){
LL n;
read(n);
LL id=(n-1)/3;
LL pos=(n-1)%3;
pair<LL,LL> ans;
ans.first=0;
ans.second=0;
for(int i=0;true;i+=2){
if (id<(1ll<<i)){
work(id,i-2,ans);
ans.first^=(1ll<<(i));
ans.second^=(1ll<<(i+1));
break;
}else id-=(1ll<<i);
}
printf("%lld\n",pos==0?ans.first:(pos==1?ans.second:(ans.first^ans.second)));
}
return 0;
}


不能打div2但又虚div1......qwq

本文作者:~Lanly~

本文链接:https://www.cnblogs.com/Lanly/p/12709501.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(284)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.