CF CodeTON Round 1
A
题意:
给定长度为\(n\)的数组\(A\),寻找一对\(1\leq i,j\leq n\),使得对于所有的\(1\leq k\leq n\),满足
\(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
*/