Codeforces Round #618 (Div. 2) 题解

A

简单模拟。


代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int T,n,a[N];
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n); int ans=0,sum=0;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++){
            if(a[i]==0) ans++,a[i]++;
            sum+=a[i];
        }
        if(sum==0) ans++;
        printf("%d\n",ans);
    } 
} 

B

手玩可得 : 将数组 \(a\) 排序后,答案即为 \(a_{n+1}-a_{n}\)


代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int T,n,a[N];
signed main(){
    scanf("%lld",&T);
    while(T--){
        scanf("%lld",&n);
        for(int i=1;i<=2*n;i++) scanf("%lld",&a[i]);
        sort(a+1,a+2*n+1);
        printf("%lld\n",a[n+1]-a[n]);
    }
}

C

题意可转化为 :从原数组中选一个数 \(x\) , 再分别将 \(x\) 与数组中其他数按位去重(即:如果两个数此位均为 1 , 则将此位修改为 0。

显然可以从高至低枚举每一位出现次数是否为 1 ,如是则选 \(x\) 为此数,并将 \(x\) 放至 \(a_1\)


代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,a[N],fac[60],vis[60],pos[60];
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    fac[0]=1; for(int i=1;i<=40;i++) fac[i]=fac[i-1]*2;
    
    for(int i=1;i<=n;i++){
        for(int j=0;j<=35;j++) if(a[i]&fac[j]) vis[j]++,pos[j]=i;
    }
    int top=1;
    for(int i=35;i>=0;i--) if(vis[i]==1){
        top=pos[i];
        break;
    }
    swap(a[1],a[top]);
    for(int i=1;i<=n;i++) printf("%lld ",a[i]);
} 

D

观察并猜结论得\(P\)\(T\) 相似,当且仅当 \(P\) 为中心对称图形,判断即可。


代码

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int n,x[N],y[N];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]);
    if(n&1){ puts("No"); return 0; }
    
    int p1=x[1]+x[n/2+1],p2=y[1]+y[n/2+1],ans=1;
    for(int i=1;i<=n/2;i++) if(x[i]+x[n/2+i]!=p1 || y[i]+y[n/2+i]!=p2) { ans=0; break; }
    (ans==1)?puts("Yes"):puts("No");
} 

E

直接做并不好做,考虑用前缀和转化:

原序列最小字典序等价于:前缀和序列最小字典序。

一段区间 \([l,r]\) 平均数为 :\(\frac{pre_r-pre_{l-1}}{r-(l-1)}\) , 观察这个式子可表示为斜率式。

对区间 \([l,r]\) 进行操作 : \(p_i \rightarrow p_{l-1}+\frac{pre_r-pre_{l-1}}{r-(l-1)}\times (i-l+1)\)

我们就将其看做点 \((0,pre_0) , (1,pre_1) ,.....(n,pre_n)\),用其维护下凸包即可。


代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
template <typename T>
inline void read(T &x){
    x=0; bool f=0; char ch=getchar();
    while(ch<'0' || ch>'9'){ f|=(ch=='-'); ch=getchar(); }
    while('0'<=ch && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
    if(f) x=-x; 
}
int n,top,a[N],pre[N],sta[N];
double slope(int x,int y){
    return (double)(pre[y]-pre[x])/(y-x);
}
signed main(){
    read(n);
    for(int i=1;i<=n;i++) read(a[i]),pre[i]=pre[i-1]+a[i];
    for(int i=1;i<=n;i++){
        while(top && slope(sta[top-1],i) < slope(sta[top-1],sta[top]) ) top--;
        sta[++top]=i;
    }
    
    for(int i=1;i<=top;i++){
        double ans=slope(sta[i-1],sta[i]);
        for(int j=1;j<=sta[i]-sta[i-1];j++) printf("%.10lf\n",ans);
    } 
}

猜你喜欢

转载自www.cnblogs.com/myblogerous/p/12290633.html