1. 程式人生 > 其它 >CF CodeTON Round 1

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

*/