CF1338 Div.1 做题记录

A

CF题面

假定用到的最大的数是 \(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

CF题面

结论题。

先看最小值,当确定一个 \(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

CF题面

规律题。

通过打表找规律可以得到,三三一组,\(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

CF题面

这场比较正常的题。

通过画图可以发现,合法的情况大概长成这个样子image
相交的图形之间有边,还原到树上,可以发现中间、间这一块大的相当于在原树上找到一个毛毛虫模型(一条链周围加几个点),求它的最大独立集。令 \(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;
}
posted @ 2023-06-08 15:32  luo_shen  阅读(34)  评论(0)    收藏  举报