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\)
#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
*/