CF CodeTON Round 1

A

题意:

给定长度为\(n\)的数组\(A\),寻找一对\(1\leq i,j\leq n\),使得对于所有的\(1\leq k\leq n\),满足

\[|a_i-a_k|+|a_k-a_j|=|a_i-a_j| \]

\(n\leq 2*10^5\)

题解:

\(a_i\)是最大值,\(a_j\)是最小值。

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-8)
    const int N=3e5+10,mod=998244353,inf=2e9;
    int n,m;
    int a[N];
    int maxn,p1,minn,p2;
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {
            cin>>n;
            p1=p2=0;
            maxn=-inf,minn=inf;
            for(int i=1;i<=n;++i)
            {
                cin>>a[i];
                if(a[i]>maxn) maxn=a[i],p1=i;
                if(a[i]<minn) minn=a[i],p2=i;
            }
            cout<<p1<<' '<<p2<<'\n';
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
4 4
zzzz
z.z.
.zzz
zzzz

*/

B

题意:

\(n\)个数的列表,每次可以从中删除某个数字\(x\),然后剩余的数字全部减去\(x\)\(n-1\)次操作后能否使剩余数字恰好为\(k\)

\(2\leq n\leq 2*10^5,1\leq k,a_i\leq 10^9\)

题解:

如果我们在第一步选择删除\(x\),第二步删除\(y\),第三步删除\(z\),看看会发生什么:

删除\(x\)\(y,z\)变为\(y-x,z-x\)

删除原来的\(y\)\(z\)变为\(z-x-(y-x)=z-y\)

如此传递下去,其实最后的剩下数字的大小就是某两个数相减的结果。

看看任意两个数字的差值是否为\(k\)就可以了。

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-8)
    const int N=3e5+10,mod=998244353,inf=2e9;
    int n,m;
    int a[N];
    map<int,int> q;
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {
            cin>>n>>m;
            q.clear();
            bool flag=0;
            for(int i=1;i<=n;++i)
            {
                cin>>a[i];
                if(q[a[i]-m]==1||q[a[i]+m]==1) flag=1;
                q[a[i]]=1;
            }
            if(flag) cout<<"YES\n";
            else cout<<"NO\n";
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
4 4
zzzz
z.z.
.zzz
zzzz

*/

C

题意:

给定一个长度为\(n\)的非负整数数组\(A\),每次可以选择一个\(x\geq 2\),让每个元素都\(mod\ x\),能否通过有限次操作让所有数字相等?

\(x\leq 10^5\)

题解:

其实可以知道如果序列中有\(0\),那么所有数字都应该模成\(0\),如果序列中有\(1\),那么所有数字都应该模成\(1\)

如果都有刚好凑一对就寄了。

然后如果都应该模成\(0\)一定可以做到,从大到小对每个数字取模它本身就行了。

最后讨论怎么都判断能否都模成\(1\)

然后我们把数组从小到大排序,如果相邻的两个数字刚好差\(1\),就永远模不成了,因为相差为\(1\)的两个数字同时取模的话,一定是一个最后为\(0\),另一个最后为\(1\)

#include<bits/stdc++.h>
using namespace std;
namespace red{
    #define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-8)
    const int N=3e5+10,mod=998244353,inf=2e9;
    int n,m;
    int a[N];
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {
            cin>>n;
            bool flag0=0,flag1=0;
            for(int i=1;i<=n;++i)
            {
                cin>>a[i];
                if(a[i]==0) flag0=1;
                if(a[i]==1) flag1=1;
            }
            sort(a+1,a+n+1);
            if(!flag1)
            {
                cout<<"YES\n";
                continue;
            }
            if(flag1&&flag0)
            {
                cout<<"NO\n";
                continue;
            }
            bool flag=0;
            for(int i=1;i<n;++i)
            {
                if(a[i]+1==a[i+1]) flag=1;
            }
            if(flag) cout<<"NO\n";
            else cout<<"YES\n";
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
4 4
zzzz
z.z.
.zzz
zzzz

*/

D

题意:

定义一个正整数\(n\)\(k-good\)的,当且仅当\(n\)可以表示为\(k\)个模\(k\)不同余的数字之和。

给定一个正整数\(n\),求\(k\geq 2\),使得\(n\)\(k-good\)的,或者表示\(k\)不存在。

\(2\leq n\leq 10^{18},T\leq 10^{15}\)

题解:

先小讨论一下特殊情况:

\(n\)是奇数,直接\(2+(n-2)\)完事。

\(n\)是偶数,找规律:

首先考虑构造一组解,如果\(n=1+2+3+…+k\),那么皆大欢喜,但事实不会这么巧。

我们还有一个调整法,那就是给任意一项加\(k\),都是符合要求的,但是事实也不会这么巧。

我们把右边的式子收缩一下\(1+2+3+……+k=\frac{(1+k)*k}{2}\)

那么给任意一项\(+k\)之后式子会怎么变化呢?假如加了\(t\)\(k\),那么式子变为\(\frac{(1+k)*k}{2}+t*k=n\)

也就是\(2n=(1+2*t+k)*k\)

那么就是把\(2n\)拆分成两个奇偶不同的数字之积。

我们把\(2n\)写错\(2n=2^s*p\)

那么\(2^s\)\(p\)中较小的那个就是\(k\),但是\(k\)不能为\(1\)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-8)
    const int N=3e5+10,mod=998244353,inf=2e9;
    int n,m,ans;
    int top,sum;
    inline int dc(int x)
    {
        return x*(x+1)/2;
    }
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {
            cin>>n;
            // if(n==6)
            // {
            //     cout<<3<<'\n';
            //     continue;
            // }
            if(n%2==1)
            {
                cout<<2<<'\n';
                continue;
            }
            int x=n,y=1;
            while(x%2==0) x/=2,y*=2;
            if(x==1)
            {
                cout<<"-1\n";
                continue;
            }
            if(y*2<=x)
            {
                cout<<y*2<<'\n';
                continue;
            }
            //y*2>x
            cout<<x<<'\n';
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
5
2
4
1516512161616
89784856616161
99999999999999998

*/

E

题意:

给定一颗无向无根树,你要为每个点安排一个权值\(a_i\),使得删除每个点后,所有连通块权值之和相等。

\(3\leq n\leq 10^5,|a_i|\leq 10^5,a_i\neq 0\)

题解:

把树二分染色,深度为奇数的节点权值为负,深度为偶数的节点权值为正,权值大小等于节点的度数。

证明:

整个树的权值之和是\(0\),因为每条边给其中一个节点\(+1\),另外一个节点\(-1\)

删除一个点后,剩下的每个连通块权值都是\(+1\)\(-1\),因为每个连通块只有一条边的平衡被打破了。

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-8)
    const int N=3e5+10,mod=998244353,inf=2e9;
    int n,m;
    int a[N];
    vector<int> eg[N];
    int dep[N],sum[N];
    inline void dfs(int now,int fa)
    {
        dep[now]=dep[fa]+1;
        for(int t:eg[now])
        {
            if(t==fa) continue;
            ++sum[t];++sum[now];
            dfs(t,now);
        }
        if(dep[now]%2==0) sum[now]=-sum[now];
    }
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {
            cin>>n;
            for(int i=1;i<=n;++i)
            {
                sum[i]=0;
                eg[i].clear();
            }
            for(int i=1;i<n;++i)
            {
                int x,y;
                cin>>x>>y;
                eg[x].push_back(y);
                eg[y].push_back(x);
            }
            dfs(1,0);
            for(int i=1;i<=n;++i) cout<<sum[i]<<" \n"[i==n];
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
4 4
zzzz
z.z.
.zzz
zzzz

*/

F

题意:

给定\(n\)个节点,每个节点权值为\(a_i\),对于任意实数\(t\),考虑以\(t\)为基础的图\(K_n(t)\),任意两个节点之间的边权为\(w_{ij}=a_i*a_j+t*(a_i+a_j)\),设\(f(t)\)\(K_n(t)\)中的最小生成树的权值和,求\(f(t)\)的上界,或说明它无上界。

题解:

\(b_i=a_i+t\),那么边权\(w_{ij}=b_i*b_j-t^2\)

从这个角度来构造最小生成树,对于每个点来说,如果\(b_i>0\),则和\(b_1\)连边,如果\(b_i<0\)则和\(b_n\)连边。

那么就是说,只有在\(t=-a_i\)的时候才会让某个点的连边状态发生改变。

只要枚举\(t\)在等于每个\(-a_i\)时的答案,通过一些预处理直接算偏移量。

\(b_i\)只是用来分析,实际求贡献不用从\(b_i\)角度考虑,因为有\(t^2\),实际上从\(a_i\)角度考虑更方便。)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-8)
    const int N=3e5+10,mod=998244353,inf=2e9;
    int n,m;
    int a[N],ans;
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {
            cin>>n;
            int tsum=0;
            for(int i=1;i<=n;++i)
            {
                cin>>a[i];
                tsum+=a[i];
            }
            //b[i]=a[i]+t
            //b[u]*b[v]-t^2
            sort(a+1,a+n+1);
            if(a[n]*(n-2)+tsum<0||a[1]*(n-2)+tsum>0)
            {
                cout<<"INF\n";
                continue;
            }
            int dv=0;
            int val=0;
            for(int i=2;i<=n;++i)
            {
                val+=a[1]+a[i];
                dv+=a[1]*a[i];
            }
            ans=-inf*inf;
            for(int i=2;i<=n;++i)
            {
                int l=-a[i],r=-a[i-1];
                ans=max(ans,max(val*l+dv,val*r+dv));
                val-=a[1];
                val+=a[n];
                dv+=a[i]*(a[n]-a[1]);
            }
            cout<<ans<<'\n';
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
4 4
zzzz
z.z.
.zzz
zzzz

*/
posted @ 2022-04-12 14:12  lovelyred  阅读(55)  评论(0)    收藏  举报