Post

CF1878(div3)题解

B. Aleksa and Stack(奇偶性构造数组)

题意:
创建一个单调递增序列,使得 $ (3 \cdot a_{i+2}) mod(a_{i+1}+a_i) !=0 $ 思路:
直接全部奇数,3*奇数=奇数,奇数+奇数=偶数

C. Vasilije in Cacak

题意:
给定n,k,x,从1-n选择k个数能组成x
思路:
选择k个数的最小值为前k个数的和,最大值为倒数k个数的和,x满足[最小值,最大值]输出YES,否则NO

D. Reverse Madness

思路:
两个区间不互相影响,在同一个区间内标记经过多少次反转,最后再判断即可

E. Iva & Pav(按位计算)

题意:
定义 $ f(l,r)=a_{l} $ & $ a_{l+1} $ &…& $ a_r $ 给出q次询问,一个k,回答最长的r使得 $f(l,r)>=k $
思路:
考虑预处理每一位,l对应的最长连续1到达的r,每次询问将每一位的r拿出来,从大到小排序,然后累加直至大于等于k则输出r,否则输出-1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void solve(){
    int n;
    cin>>n;
    vector<int> a(n+1);
    for(int i=1;i<=n;i++)cin>>a[i];
    vector<vector<int>> pos(31,vector<int>(n+1,-1));
    for(int k=0;k<=30;k++){
        for(int i=n,j=n;i>=1;i--){
            if((a[i]>>k)&1){
                j=i;
                pos[k][j]=i;
                while(j-1>=1&&((a[j-1]>>k)&1)){
                    j--;
                    pos[k][j]=i;
                }
                i=j;
           }
        }
    }
    int q;
    cin>>q;
    while(q--){
        int l,k;
        cin>>l>>k;
        ll tmp=0;
        ll ans=INF;
        vector<pair<int,int>> B; 
        for(int i=0;i<=30;i++){
            if(pos[i][l]!=-1){
                B.pb({pos[i][l],i});
            }
        }
        sort(all(B));
        bool g=0;
        for(int i=B.size()-1;i>=0;i--){
            tmp+=(1ll<<B[i].second);
            if(tmp>=k){
                cout<<B[i].first<<" ";
                g=1;
                break;
            }
        }
        if(g)continue;
        cout<<"-1 ";
    }
    cout<<"\n";
}

F. Vasilije Loves Number Theory(数论)

题意:
给定一个整数n,每次进行下列操作,定义d(n)为n的约数

  • 1 x,n*=x,然后找出一个a,满足 $ d(n \cdot a)=n,gcd(a,n)=1 $
  • 2,重置n

思路:
定理: $n=a_1^{b_1} \cdot a_2^{b_2} \cdot a_3^{b_3}..$,约数个数= $ (b_1+1) \cdot (b_2+1) \cdot (b_3+1)…$
如果n能整除此时n的约数个数,则a可以是若干个质因数组成,使得d(na)=n,问题转换完成
注意:n
x是个大数,每次计算要用比较质因数的次数来判断是否能被整除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
void solve(){
    ll nn,q;
    cin>>nn>>q;
    map<ll,ll> cnt[1010];
    ll tmp=nn;
    vector<pll> pos;
    for(int i=2;i<=sqrt(tmp);i++){
        if(tmp%i==0){
            int a=i,b=0;
            while(tmp%i==0)tmp/=i,b++;
            pos.pb({a,b});
        }
    }
    if(tmp>1){
        pos.pb({tmp,1});
    }
    for(auto it:pos){
        for(int i=0;i<=q;i++){
            cnt[i][it.first]=it.second;
        }
    }
    ll v=0;
    __int128 N=nn;
    __int128 n=nn;
    while(q--){
        int op;
        cin>>op;
        if(op==1){
            ll x;
            cin>>x;
            n*=x;
            for(int i=2;i<=sqrt(x);i++){
                if(x%i==0){
                    int a=i,b=0;
                    while(x%i==0)x/=i,b++;
                    cnt[v][a]+=b;
                }
            }
            if(x>1)cnt[v][x]++;
            ll A=1;
            map<int,int> P;
            for(auto it:cnt[v]){
                int H=it.second+1;
                for(int i=2;i<=sqrt(H);i++){
                    if(H%i==0){
                        int a=i,b=0;
                        while(H%i==0)H/=i,b++;
                        P[a]+=b;
                    }
                }
                if(H>1)P[H]++;
            }
            bool g=0;
            for(auto it:P){
                if(cnt[v][it.first]<P[it.first]){
                    g=1;
                    break;
                }
            }
            if(!g)cout<<"YES\n";
            else cout<<"NO\n";
        }
        else{
            v++;
            n=N;
        }
    }
    cout<<"\n";
}

G. wxhtzdy ORO Tree(LCA)

一棵树每次询问两个节点x,y,在两个点的最短路径中找出一个z,使g(x,z)+g(y,z)最大,g(u,v)表示a[u]一直或到a[v],然后计算二进制1的数量
思路:
对于x的每一位考虑,找出离x最近的一个数且该位数为1,最多找 $ log2(max(a_i)) $ 位,位数为0的可以忽略因为对x和y都不会有贡献,全部找出来x和y的(还要判断最近的点是否在lca和自身之间),然后再对每个数都跑一遍(用倍增跑)统计
复杂度: $ O(q \cdot (logn+log(max(a))) \cdot logn) $

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
const int M=200010;
int fa[M][30],sum[M][30],depth[M],a[M],bst[M][30];
vector<int> adj[M];
void dfs(int u,int p,vector<int> b){
    fa[u][0]=p;
    sum[u][0]=a[p];
    depth[u]=depth[p]+1;
    for(int i=0;i<30;i++){
        bst[u][i]=b[i];
        if(a[u]&(1ll<<i))b[i]=u;
    }
    for(int i=1;i<=log2(depth[u]);i++){
        fa[u][i]=fa[fa[u][i-1]][i-1];
        sum[u][i]=sum[u][i-1]|sum[fa[u][i-1]][i-1];
    }
    for(auto v:adj[u]){
        if(v!=p){
            dfs(v,u,b);
        }
    }
}
int lca(int x,int y){
    if(depth[x]<depth[y])swap(x,y);
    while(depth[x]>depth[y]){
        x=fa[x][(int)log2(depth[x]-depth[y])];
    }
    if(x==y)return x;
    for(int k=log2(depth[x]);k>=0;k--){
        if(fa[x][k]!=fa[y][k])x=fa[x][k],y=fa[y][k];
    }
    return fa[x][0];
}
int getOR(int u,int dis){
    int res=a[u];
    for(int i=0;i<30;i++){
        if(dis&(1<<i)){
            res|=sum[u][i];
            u=fa[u][i];
        }
    }
    return res;
}
int query(int u,int v){
    int l=lca(u,v);
    return getOR(u,depth[u]-depth[l])|getOR(v,depth[v]-depth[l]);
}
void solve(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        adj[i].clear();
        depth[i]=0;
        for(int k=0;k<30;k++){
            fa[i][k]=sum[i][k]=bst[i][k]=0;
        }
    }
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    vector<int> temp(30,-1);
    dfs(1,0,temp);
    int q;
    cin>>q;
    while(q--){
        int x,y;
        cin>>x>>y;
        int LCA=lca(x,y);
        vector<int> t;
        t.push_back(x);
        t.push_back(y);
        for(int i=0;i<30;i++){
            if(bst[x][i]!=-1&&lca(LCA,bst[x][i])==LCA)t.push_back(bst[x][i]);
            if(bst[y][i]!=-1&&lca(LCA,bst[y][i])==LCA)t.push_back(bst[y][i]);
        }
        int ans=__builtin_popcount(a[x])+__builtin_popcount(a[y]);
        for(auto p:t){
            int x1=a[x]|query(x,p),x2=a[y]|query(y,p);
            ans=max(ans,__builtin_popcount(x1)+__builtin_popcount(x2));
        }
        cout<<ans<<" ";
    }
    cout<<"\n";
}
This post is licensed under CC BY 4.0 by the author.