Codeforces Round #633 (Div. 1)
A. Powered Addition (CF 1338 A)
题目大意
给定一个个数字的数组,对于每一个正整数,你可以选择若干个数字,使得。当然你也可以不进行选择。求最小的数字,使得当取过了~进行操作后,数组是一个非递减数组。
解题思路
从左到右,如果,我们就把变成,并记录最大的,最大值在二进制下的位数即是答案。
操作就很简单,差值在二进制下第位是1就在的时候选择那个数就好了。
神奇的代码
#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)
题目大意
给定一棵无权树,要求对边赋一个正权值,使得任意两个叶子节点之间的路径权值异或和为。求所赋的不同权值数的最小值和最大值。
解题思路
如果任意两个叶子节点之间的路径长度是偶数,那么我们对全部边赋即可,最小为。
如果存在奇数长度的,注意到。我们把不与叶子节点相连的边赋为,是奇数长度的那对叶子节点相连的边,一个赋,一个赋,那其他叶子节点对于这两个叶子节点,如果是偶数路径,则与其叶子节点相连的边的权值一样,奇数路径则相反(变、变)。
对于不是的一对点,它们的边权异或和一定为,因为边权异或和可以拆成,因为的到的边权异或了两次抵消掉了。而在前面的构造里我们知道,所以。也即最小为。
判断奇数长度的,从一个叶子节点搜(初始深度为)发现有深度是偶数深度的叶子节点即可得知有奇数长度。
至于最大的,我们可以设想,除了叶子节点相连的边,其他的边都填不同的数,然后选择一个叶子节点,其边也填一个不同的数,然后对于其他叶子节点,其边填(a,fa[b])的值(fa[b]表示与叶子节点相连的边的另外一个节点)。对于不是叶子节点的点,其也一定为,证明也如同上面的方法,将。
由于可以填的数无穷大,我们可以证明 (猜想) 这一定可以做到的。
所以,只有那些一个节点连了多个叶子节点的那些边的权值一定相等外,其他的都可以不一样。
神奇的代码
#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)
题目大意
有一个有无穷无尽个正整数的数组,其构造方法如下:
- (a,b,c)是可选中的字典序最小的一组
- 把a,b,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 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; }
不能打但又虚......
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/12709501.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步