Codeforces Round #678 (Div. 2) A,B,C,D,E

A. Reorder

判断一下所有元素加和是否等于m即可。

#include <bits/stdc++.h>
using namespace std;
int T;
int n,m;
int sum;
int main()
{
    
    
    scanf("%d",&T);
    while(T--)
    {
    
    
        scanf("%d%d",&n,&m);
        int x;
        sum=0;
        while(n--)
        {
    
    
            scanf("%d",&x);
            sum+=x;
        }
        if(sum==m)
        puts("YES");
        else
        puts("NO");
    }
    return 0;
}

B. Prime Square

n很小随便搞,我是直接+4,+6,+8…这样做的,也可以像答案一样用0,1(比赛时候以为不能用0QAQ)

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
long long su[maxn],cnt;
bool isprime[maxn];
int a[maxn];
void prime()
{
    
    
    cnt=1;
    memset(isprime,1,sizeof(isprime));//初始化认为所有数都是素数
    isprime[0]=isprime[1]=0;//0和1不是素数
    for(long long i=2;i<=maxn;i++)
    {
    
    
        if(isprime[i])
        su[cnt++]=i;//保存素数i
        for(long long j=1;j<cnt&&su[j]*i<=maxn;j++)
        {
    
    
            isprime[su[j]*i]=0;//筛掉小于等于i的素数和i的积构成的合数
        }
    }
}
int main()
{
    
    
    int T;
    prime();
    scanf("%d",&T);
    while(T--)
    {
    
    
        int n;
        scanf("%d",&n);
        a[0]=1;
        int sum=1;
        for(int i=1;i<n;++i)
        {
    
    
            for(int j=4;;j+=2)
            {
    
    
                if(isprime[sum+j])
                {
    
    
                    a[i]=j;
                    sum+=j;
                    break;
                }
            }
        }
        for(int j=0;j<n;++j)
        {
    
    
            for(int i=0;i<n;++i)
            {
    
    
                printf("%d ",a[(i+j)%n]);
            }
            puts("");
        }
    }
    return 0;
}

C. Binary Search

利用二分的过程,判断一下必须向右跳的有几个,必须向左跳的有几个,然后排列计算一下即可。

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int N=1e3+5;
int n,x,pos;
ll A[N][N];
int main()
{
    
    
    scanf("%d%d%d",&n,&x,&pos);
    A[0][0]=1;
    for(int i=1;i<=n;++i)
    {
    
    
        A[i][0]=1;
        for(int j=1;j<=i;++j)
        {
    
    
            A[i][j]=(i-j+1)*A[i][j-1]%mod;
        }
    }
    int le,gr;
    le=gr=0;
    int l=0;
    int r=n;
    while(l<r)
    {
    
    
        int mid=(l+r)>>1;
        if(mid<=pos)
        {
    
    
            if(mid!=pos)
            le++;
            l=mid+1;
        }
        else
        {
    
    
            gr++;
            r=mid;
        }
    }
    //cout<<le<<" "<<gr<<endl;
    printf("%lld\n",A[x-1][le]*A[n-x][gr]%mod*A[n-le-gr-1][n-le-gr-1]%mod);
    return 0;
}

D. Bandit in a City

这题就是要使叶子节点的权值尽可能平均,那对于一个节点如何知道怎样分配才能使其叶子节点平均呢。只需要从叶子节点向上,维护当前叶子节点最大值,叶子节点数,叶子节点权值和。然后判断当前所有叶子节点的权值和 sum + 当前点的值v 是否> 当前叶子节点最大值max*当前叶子节点数,如果小于说明还不能使所有叶子节点权值到max,否则就可以让所有节点权值到max,然后利用平均分配原则,使剩下的值平均的分给每个叶子,更新max。最后根节点的max就是答案。

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int head[N];
struct node
{
    
    
    int to,next;
}edge[N];
ll a[N];
struct e
{
    
    
    ll ma;
    ll num;
    ll sum;
}p[N];
int n;
int cnt;
void add(int x,int y)
{
    
    
    edge[++cnt].to=y;
    edge[cnt].next=head[x];
    head[x]=cnt;
}
void dfs(int u,int fa)
{
    
    
    bool flag=0;
    ll ma=0;
    ll s=0;
    ll nb=0;
    for(int i=head[u];i;i=edge[i].next)
    {
    
    
        flag=1;
        int v=edge[i].to;
        dfs(v,u);
        ma=max(ma,p[v].ma);
        s+=p[v].sum;
        nb+=p[v].num;
    }
    if(!flag)//р╤вс╫з╣Ц
    {
    
    
        p[u].ma=a[u];
        p[u].sum=a[u];
        p[u].num=1;
    }
    else
    {
    
    
        if(a[u]+s>ma*nb)
        {
    
    
            ll t=a[u]+s-ma*nb;
            ma+=t/nb;
            if(t%nb)
            ma++;
        }
        p[u].ma=ma;
        p[u].sum=s+a[u];
        p[u].num=nb;
    }
}
int main()
{
    
    
    scanf("%d",&n);
    for(int i=2;i<=n;++i)
    {
    
    
        int x;
        scanf("%d",&x);
        add(x,i);
    }
    for(int i=1;i<=n;++i)
    scanf("%lld",&a[i]);
    dfs(1,0);
    printf("%lld\n",p[1].ma);
    return 0;
}

E. Complicated Computations

我们需要找到最后mex序列的所有元素,那么考察每一个元素是否出现在最后mex即可。对于一个数k,如果其为某序列mex,那么其在序列肯定没出现,并且1~k-1都出现了。那么在原始序列,就是看1~k-1最小的位置,是否出现在上一次k出现的位置之前,如果出现在上一次k出现的位置之前,那么此时mex就是最小的那个,否则就是k。这个过程可以用线段树模拟。

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n;
int a[N];
bool vis[N];//记录该数是否出现过
int last[N];//记录该数上一次出现的位置
int mi[N<<4];//维护1-k-1最小出现位置
void push_up(int k)
{
    
    
    mi[k]=min(mi[k<<1],mi[k<<1|1]);
}
void update(int k,int l,int r,int pos,int v)
{
    
    
    if(l==r)
    {
    
    
        mi[k]=v;
        return ;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)
    update(k<<1,l,mid,pos,v);
    else
    update(k<<1|1,mid+1,r,pos,v);
    push_up(k);
}
int query(int k,int l,int r,int v)
{
    
    
    if(l==r)
    return l;
    int mid=(l+r)>>1;
    if(mi[k<<1]<v)
    return query(k<<1,l,mid,v);
    else
    return query(k<<1|1,mid+1,r,v);
}
int main()
{
    
    
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    scanf("%d",&a[i]);
    for(int i=1;i<=n;++i)
    {
    
    
        int x=a[i];
        if(last[x]+1<i)
        vis[query(1,1,N-1,last[x]+1)]=1;
        last[x]=i;
        update(1,1,N-1,x,i);
    }
    for(int i=1;i<=N-1;++i)
    {
    
    
        if(last[i]&&last[i]!=n)
        vis[query(1,1,N-1,last[i]+1)]=1;
    }
    vis[query(1,1,N-1,1)]=1;
    for(int i=1;i<=N-1;++i)
    {
    
    
        if(!vis[i])
        {
    
    
            printf("%d\n",i);
            return 0;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_44491423/article/details/109388667