Codeforces Round #670 (Div. 2)(A B C D)
题目列表
- A. Subset Mex
- B. Maximum Product
- C. Link Cut Centroids
- D. Three Sequences
Practice link:https://codeforces.ml/contest/1406
A. Subset Mex
思路:从小到大遍历,出现两次及以上的数字一定不会是mex,答案一定是出现次数为1的最小数字加上出现次数为0的最小数字。
代码:
#define MOD 1000000007
#define ll long long
#define mem(a,x) memset(a,x,sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const double eps = 1e-4;
const long long INF = 0x3f3f3f3f3f3f3f3fLL;
const int inf = 0x3f3f3f3f;
int a[105];
int sum[105];
int main()
{
int T,n;
scanf("%d",&T);
while(T--){
mem(sum,0);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[a[i]]++;
}
sort(a+1,a+n+1);
int k=-1;
int num=0;
for(int i=0;i<=100;i++){
if(sum[i]>=2)continue;
if(sum[i]==1&&k==-1){
num+=i;
k=i;
}
if(sum[i]==0&&k!=-1){
num+=i;
break;
}
if(sum[i]==0&&k==-1){
num+=i*2;
break;
}
}
printf("%d\n",num);
}
}
B. Maximum Product
思路:首先题意直接转化为从a数组中取五个数,使这五个数相乘的答案最大。那么把数组从大到小排序。然后考虑有负数,那么答案就是
1、\(a[1]\times a[2]\times a[n-2]\times a[n-1]\times a[n]\)
2、\(a[1]\times a[2]\times a[3]\times a[4]\times a[n]\)
3、\(a[n-4]\times a[n-3]\times a[n-2]\times a[n-1]\times a[n]\)
这三个数中取max即可。
代码:
const long long INF = 0x3f3f3f3f3f3f3f3fLL;
const int inf = 0x3f3f3f3f;
ll a[100005];
int main()
{
int T,n;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
sort(a+1,a+n+1);
ll num=-INF;
num=max(num,a[1]*a[2]*a[n]*a[n-1]*a[n-2]);
num=max(num,a[n]*a[n-1]*a[n-2]*a[n-3]*a[n-4]);
num=max(num,a[1]*a[2]*a[3]*a[4]*a[n]);
printf("%lld\n",num);
}
}
C. Link Cut Centroids
题意:让你在一棵树中去掉一条边,然后添加一条边,让这棵树的重心唯一。
思路:首先dfs求出树的重心,如果只有一个重心,那么随便去掉一条,再添加回来即可。如果有两个重心,那么去掉两个重心的连线,然后用其中一个重心去连接另一个重心的子树上的随意一点即可。
代码:
const int maxn = 100005 ;
vector<int>tree[maxn];
vector<int>num[100005];
int minNode,minBalance;
//minNode 表示当前的重心
//minBalance 表示当前重心下的最大子树结点个数
int d[maxn];
//d[i]表示以 i 为根的子树结点数
int n;
void getCentroid(int u,int fa)
{
d[u]=1;
int maxsub=0;
for(int i=0;i<tree[u].size();i++){
int v=tree[u][i];
if(v==fa)continue;
getCentroid(v,u);
d[u]+=d[v];
maxsub=max(d[v],maxsub);
}
maxsub=max(maxsub,n-d[u]);
if(maxsub<minBalance){
minNode=u;
minBalance=maxsub;
num[maxsub].push_back(u);
}else if(maxsub==minBalance){
num[maxsub].push_back(u);
}
}
vector<int>gg;
void dfs(int u,int fa)
{
if(gg.size()==1)return;
if(tree[u].size()==1){
gg.push_back(u);
return;
}
for(int i=0;i<tree[u].size();i++){
int v=tree[u][i];
if(v==fa)continue;
dfs(v,u);
}
}
int main()
{
int T;
cin>>T;
while(T--){
cin>>n;
gg.clear();
for(int i=1;i<=n;i++){
tree[i].clear();
num[i].clear();
}
for(int i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
tree[u].push_back(v);
tree[v].push_back(u);
}
minNode=0;
minBalance=inf;
getCentroid(1, 0);
//printf("%d %d\n",minNode,minBalance);
if(num[minBalance].size()==1){
printf("1 %d\n",tree[1][0]);
printf("1 %d\n",tree[1][0]);
}else{
//printf("%d %d\n",num[minBalance][0],num[minBalance][1]);
int u=num[minBalance][1];
int fa=num[minBalance][0];
for(int i=0;i<tree[u].size();i++){
int v=tree[u][i];
if(v!=fa){
printf("%d %d\n",u,v);
printf("%d %d\n",num[minBalance][0],v);
break;
}
}
}
}
return 0;
}
D. Three Sequences
题意:给你一个数组\(a_{i}\),让你去构造\(b_{i}\)和\(c_{i}\),\(b_{i}\)单调不增,\(c_{i}\)单调不减,让你使max(\(b_{i}\),\(c_{i}\))最小。在给你q次修改,把区间\(\left[ l,r\right]\)加上x,并求出 max(\(b_{i}\),\(c_{i}\))。
思路:
代码:
#define ll long long
#define MOD 1000000007
#define mem(a,x) memset(a,x,sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const long long INF = 0x3f3f3f3f3f3f3f3fLL;
const int inf = 0x3f3f3f3f;
const int MAXN=16005;
const int MAXM=80005;
int a[100005];
ll differ[100005];
int n,q;
ll tot=0;
int main()
{
tot=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(i>1){
differ[i]=a[i]-a[i-1];
if(differ[i]>0){
tot+=differ[i];
}
}
}
differ[1]=a[1];
ll num=(differ[1]-tot)/2;
printf("%lld\n",max(num+tot,differ[1]-num));
scanf("%d",&q);
while(q--){
int l,r;
ll x;
scanf("%d%d%lld",&l,&r,&x);
if(l==1){
differ[1]+=x;
}else{
if(x<0){
if(differ[l]>0)tot-=min(differ[l],-x);
}else{
if(differ[l]+x>0)tot+=min(x,differ[l]+x);
}
differ[l]+=x;
}
if(r+1<=n){
if(x>0){
if(differ[r+1]>0){
tot-=min(differ[r+1],x);
}
}else{
if(differ[r+1]-x>0){
tot+=min(-x,differ[r+1]-x);
}
}
differ[r+1]-=x;
}
num=(differ[1]-tot)/2;
printf("%lld\n",max(num+tot,differ[1]-num));
}
return 0;
}
越自律,越自由