A
假定用到的最大的数是 \(x\),那么一个数最大可以增大 \(2^x-1\)。题目只要求不降,所以求出将 \(a_i<a_{i-1}\) 变成 \(a_i=a_{i-1}\) 时需要增大的最大值。求出这个数的二进制位数即可。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=1e5+10;
int n,a[N];
void solve(){
read(n);
int mx=0;
for(int i=1;i<=n;i++){
read(a[i]);
if(i>=2){
mx=max(mx,a[i-1]-a[i]);
a[i]=max(a[i],a[i-1]);
}
}
int ans=0;
while(mx){
ans++;
mx>>=1;
}
write_endl(ans);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t;
read(t);
while(t--){
solve();
}
return 0;
}
B
结论题。
先看最小值,当确定一个 \(deg\not =1\) 的点为根时,若所有叶子节点的 \(dis\) 奇偶性相同,则为 \(1\),否则为 \(3\)。前者显然,后者考虑设计一个构造方案。令 \(dis\) 为奇数的点为奇点,\(dis\) 为偶数的为偶点。将奇点到父亲的边权赋为 \(1\),将偶点到父亲的边权赋为 \(2\),将剩下的边权赋为 \(3\)。这样构造,偶点到偶点和奇点到奇点的路径异或和一定为 \(0\),对于一个奇点到偶点的路径 \((u,v)\),\(u\) 到 \(lca\) 的距离 \(dis_{u,lca}\) 和 \(v\) 到 \(lca\) 的距离 \(dis_{v,lca}\) 必然一奇一偶,这意味着路径上会有奇数个 \(3\),相互抵消后就是 \(1\oplus 3\oplus 2\),异或和为 \(0\)。
再看最大值,因为权值可以赋无穷大,所以异或值相同的路径有很多种,我们需要考虑的只是 \(dis=2\) 的路径,即父亲相同的两个叶子节点,两个数异或和为 \(0\) 只能是两个数相同,所以一个点到叶子节点的边权必须相同。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=1e5+10;
int n,flag[N],tot[N],dis[N],x;
vector<int>e[N];
void dfs(int u,int fa){
if(flag[u]){
x=(dis[u]&1);
}
for(auto v:e[u]){
if(v==fa){
continue;
}
tot[u]+=flag[v];
dis[v]=dis[u]+1;
dfs(v,u);
}
}
void solve(){
read(n);
for(int i=1,u,v;i<n;i++){
read(u),read(v);
e[u].pb(v);
e[v].pb(u);
}
int rt=0;
for(int i=1;i<=n;i++){
if(e[i].size()!=1){
rt=i;
}
else{
flag[i]=1;
}
}
dfs(rt,0);
bool fl=0;
for(int i=1;i<=n;i++){
if(flag[i]){
if(x^(dis[i]&1)){
fl=1;
}
}
}
if(fl){
write_space(3);
}
else{
write_space(1);
}
int ans=n-1;
for(int i=1;i<=n;i++){
if(tot[i]){
ans-=(tot[i]-1);
}
}
write_endl(ans);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
C
规律题。
通过打表找规律可以得到,三三一组,\(a\) 的值域范围只为 \(2^{2x}\sim 2^{2x+1}-1,x\in N\),对应的 \(b\) 值域范围为 \(2^{2x+1}\sim 2^{2x+1}+2^x-1,x\in N\),且将其划分为四块后,出现的顺序为 \(1,3,4,2\),划分后的块依然满足这个性质。所以我们可以找到 \(a\) 属于哪个块,\(b\) 递归寻找,\(c=a^b\)。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
int n;
struct node{
int a,b,c;
};
int dfs(int B,int idx){
if(!B){
return 0;
}
if(idx<=B){
return dfs(B/4,idx);
}
else if(idx<=2*B){
return 2*B+dfs(B/4,idx-B);
}
else if(idx<=3*B){
return 3*B+dfs(B/4,idx-B*2);
}
else{
return B+dfs(B/4,idx-B*3);
}
}
node query(int tot){
int B=1,st=1;
while(st+B<=tot){
st+=B;
B<<=2;
}
node res;
res.a=B+tot-st;
res.b=dfs(B/4,tot-st+1)+B*2;
res.c=res.b^res.a;
return res;
}
void solve(){
read(n);
node x=query((n-1)/3+1);
if(n%3==1){
write_endl(x.a);
}
else if(n%3==2){
write_endl(x.b);
}
else{
write_endl(x.c);
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t;
read(t);
while(t--){
solve();
}
return 0;
}
D
这场比较正常的题。
通过画图可以发现,合法的情况大概长成这个样子
相交的图形之间有边,还原到树上,可以发现中间、间这一块大的相当于在原树上找到一个毛毛虫模型(一条链周围加几个点),求它的最大独立集。令 \(f_{u,0/1}\) 表示点 \(u\) 不选/选,最大独立集的大小。
可以写出方程式
\(f_{u,0}=\max\{\max(f_{v,0},f_{v,1})\}+(deg_u-2)\times[deg_u\ge 2]\)
\(f_{u,1}=\max\{f_{v,0}\}+1\)
其中 \(deg_u-2\) 表示忽略选择的儿子和父亲,其它儿子都可以被选择,且选择更优。答案在中途统计即可。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=1e5+10;
int n,f[N][2],ans;
vector<int>e[N];
void dfs(int u,int fa){
f[u][0]=f[u][1]=0;
for(auto v:e[u]){
if(v==fa){
continue;
}
dfs(v,u);
ans=max(ans,f[u][1]+f[v][0]+1);
ans=max(ans,f[u][0]+(int)(e[u].size())-2+max(f[v][0],f[v][1]));
f[u][1]=max(f[u][1],f[v][0]);
f[u][0]=max(f[u][0],max(f[v][0],f[v][1]));
}
f[u][1]++;
if(e[u].size()>=2){
f[u][0]+=e[u].size()-2;
}
ans=max(ans,f[u][0]);
ans=max(ans,f[u][1]);
}
void solve(){
read(n);
for(int i=1;i<n;i++){
int u,v;
read(u),read(v);
e[u].pb(v);
e[v].pb(u);
}
dfs(1,0);
write_endl(ans);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}