牛客练习赛26

A.平面

这是道好题,考验的是我们的数学能力。

我们可以把X分成两条直线,这不就转化为了n条互不相交直线最多能把平面分成多少部分。

我们知道一个公式:n*(n+1)/2

时间复杂度O(1)

#include<bits/stdc++.h>
using namespace std;
long long n;
int main()
{
    scanf("%lld",&n);
    n*=2;
    cout<<n*(n+1)/2+1;
    return 0;
}

B.烟花

好题,中等难度。

我一看题目就知道这是道期望dp题。

对于第1个问题,f[i]表示前i个烟花产生颜色的期望。

for(int i=1;i<=n;i++)
    f[i]=(f[i-1]+1.0)*p[i]+f[i-1]*(1.0-p[i]);

对于第2个问题,表示前i个烟花产生j种颜色的概率。(注意要滚存)

g[0]=(1-p[1]);g[1]=p[1];
for(int i=2;i<=n;i++)
{
    for(int j=min(i,k);j;j--)
        g[j]=g[j-1]*p[i]+g[j]*(1.0-p[i]);
    g[0]*=(1-p[i]);
}

时间复杂度:O(n*k)

全部代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,k;
double p[N],f[N],g[N];
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)scanf("%lf",&p[i]);
    for(int i=1;i<=n;i++)
        f[i]=(f[i-1]+1.0)*p[i]+f[i-1]*(1.0-p[i]);
    printf("%.4lf\n",f[n]);
    g[0]=(1-p[1]);g[1]=p[1];
    for(int i=2;i<=n;i++)
    {
        for(int j=min(i,k);j;j--)
            g[j]=g[j-1]*p[i]+g[j]*(1.0-p[i]);
        g[0]*=(1-p[i]);
    }
    printf("%.4lf",g[k]);
    return 0;    
}

C.城市规划

这题卡了我好久,我还以为可以用监视任务这题的方法,用线段树+贪心做。

但调了好久发现会T(m竟然=1e7)

这题由于只要区间>=1所以,我们就可以用一种简单的方法。

我们发现对于每个右端点,只有最大的左端点有用(想一想为什么)

时间复杂度:O(n)

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,a[N];
char buf[1<<21],*p1=buf,*p2=buf;
inline int gc()
{
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    int ret=0,f=0;
    char c=gc();
    while(!isdigit(c))
    {
        if(c=='-')f=1;
        c=gc();
    }
    while(isdigit(c))
    {
        ret=ret*10+c-48;
        c=gc();
    }
    if(f)return -ret;
    return ret;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        int x=0;x=read();
        int y=0;y=read();y--;
        a[y]=max(a[y],x);
    }
    int pre=0,ans=0;
    for(int i=1;i<=n;i++)
        if(a[i]&&pre<a[i])
        {
            ans++;
            pre=i;
        }
    printf("%d",ans);
    return 0;
}

D. xor序列

这题不是线性基裸题吗。

xor有个性质:a xor b =c 那么 a xor c = b

直接查找 a xor b 是否有,有就YES,否则NO

时间复杂度O(50*n)

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,x,y,m,p[55];
void add(int x)
{
    for(int i=50;i>=0;i--)
    {
        if((x>>i)==0)continue;
        if(!p[i])
        {
            p[i]=x;
            break;
        }
        x^=p[i];
    }
}
bool pd(int x)
{
    for(int i=50;i>=0;i--)
    {
        if((x>>i)==0)continue;
        if(!p[i])return false;
        x^=p[i];
    }
    return true;
}
signed main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&x);
        add(x);
    }
    scanf("%lld",&m);
    while(m--)
    {
        scanf("%lld%lld",&x,&y);
          if(pd(x^y))puts("YES");
          else puts("NO");
    }
    return 0;
}

E. 树上路径

这题真的难,不仅思维上难,代码实现上很难(这是我们学校的一场模拟赛的一道题,我现场A了)。

这题一看就是要用树链剖分,关键是如何维护(u, v)路径上节点的权值两两相乘的和 。

我们记一个sum数组表示和,在记一个mul数组记录两两相乘的和。

我们发现如果l-r这段区间集体+val,那么

tree[nod].mul=(tree[nod].mul+(r-l)*tree[nod].sum%p*val%p+(val*val)%p*jc[r-l]%p)%p;
tree[nod].sum=(tree[nod].sum+(r-l+1)*val%p)%p;
lazy[nod]=(lazy[nod]+val)%p;

jc[i]=sigema(1-i)

所以这题就这么愉快的解决了

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define mid (l+r)/2
const int p=1000000007;
const int N=1000005;
int n,m,opt,x,y,z,tot,val[N],jc[N],fa[N],size[N],dep[N],son[N],top[N],seg[N],rev[N],head[N],lazy[N*4];
struct node{
    int sum,mul;
}tree[N*4];
struct node2{
    int too,next;
}edge[N*2];
void add(int a,int b)
{
    edge[++tot].too=b;edge[tot].next=head[a];head[a]=tot;
}
void dfs1(int u,int f)
{
    fa[u]=f;size[u]=1;dep[u]=dep[f]+1;
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].too;
        if(v==f)continue;
        dfs1(v,u);
        size[u]+=size[v];
        if(size[v]>size[son[u]])son[u]=v;
    }
}
void dfs2(int u,int f)
{
    if(son[u])
    {
        seg[son[u]]=++seg[0];
        rev[seg[0]]=son[u];
        top[son[u]]=top[u];
        dfs2(son[u],u);
    }
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].too;
        if(!top[v])
        {
            seg[v]=++seg[0];
            rev[seg[0]]=v;
            top[v]=v;
            dfs2(v,u);
        }
    }
}
void pushup(int nod)
{
    tree[nod].sum=(tree[nod*2].sum+tree[nod*2+1].sum)%p;
    tree[nod].mul=(tree[nod*2].mul+tree[nod*2+1].mul+tree[nod*2].sum*tree[nod*2+1].sum%p)%p;
}
void bian(int nod,int l,int r,int val)
{
    tree[nod].mul=(tree[nod].mul+(r-l)*tree[nod].sum%p*val%p+(val*val)%p*jc[r-l]%p)%p;
    tree[nod].sum=(tree[nod].sum+(r-l+1)*val%p)%p;
    lazy[nod]=(lazy[nod]+val)%p;   
}
void pushdown(int nod,int l,int r)
{
    bian(nod*2,l,mid,lazy[nod]);
    bian(nod*2+1,mid+1,r,lazy[nod]);
    lazy[nod]=0;   
}
void build(int nod,int l,int r)
{
    if(l==r)
    {
        tree[nod].sum=val[rev[l]]%p;
        tree[nod].mul=0;
        return;
    }
    build(nod*2,l,mid);
    build(nod*2+1,mid+1,r);
    pushup(nod);
}
void add(int nod,int l,int r,int L,int R,int val)
{
    if(l==L&&r==R)
    {
        tree[nod].mul=(tree[nod].mul+(r-l)*tree[nod].sum%p*val%p+(val*val)%p*jc[r-l]%p)%p;
        tree[nod].sum=(tree[nod].sum+(r-l+1)*val%p)%p;
        lazy[nod]=(lazy[nod]+val)%p;
        return;
    }
    pushdown(nod,l,r);
    if(R<=mid)add(nod*2,l,mid,L,R,val);
    else if(L>mid)add(nod*2+1,mid+1,r,L,R,val);
    else{
        add(nod*2,l,mid,L,mid,val);
        add(nod*2+1,mid+1,r,mid+1,R,val);
    }
    pushup(nod);
}
node query(int nod,int l,int r,int L,int R)
{
    if(l==L&&r==R)return tree[nod];
    pushdown(nod,l,r);
    if(R<=mid)return query(nod*2,l,mid,L,R);
    else if(L>mid)return query(nod*2+1,mid+1,r,L,R);
    else{
        node a=query(nod*2,l,mid,L,mid);
        node b=query(nod*2+1,mid+1,r,mid+1,R);
        node c;
        c.sum=(a.sum+b.sum)%p;
        c.mul=(a.mul+b.mul+a.sum*b.sum%p)%p;
        return c;
    }
}
void add2(int x,int y,int val)
{
    int fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy);
        add(1,1,seg[0],seg[fx],seg[x],val);
        x=fa[fx];fx=top[x];
    }
    if(dep[x]>dep[y])swap(x,y);
    add(1,1,seg[0],seg[x],seg[y],val);
}
int find(int x,int y)
{
    int fx=top[x],fy=top[y];
    node xu,jia;
    jia.sum=0;jia.mul=0;
    while(fx!=fy)
    {
        if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy);
        xu=query(1,1,seg[0],seg[fx],seg[x]);
        jia.mul=(jia.mul+xu.mul+jia.sum*xu.sum%p)%p;
        jia.sum=(jia.sum+xu.sum)%p;
        x=fa[fx];fx=top[x];
    }
    if(dep[x]>dep[y])swap(x,y);
    xu=query(1,1,seg[0],seg[x],seg[y]);
    jia.mul=(jia.mul+xu.mul+jia.sum*xu.sum%p)%p;
    jia.sum=(jia.sum+xu.sum)%p;
    return jia.mul;
}
signed main()
{
    scanf("%lld%lld",&n,&m);
    jc[1]=1;
    for(int i=2;i<=n;i++)jc[i]=(jc[i-1]+i)%p;
    for(int i=1;i<=n;i++)scanf("%lld",&val[i]);
    for(int i=1;i<n;i++)
    {
        scanf("%lld%lld",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs1(1,0);
    seg[0]=seg[1]=rev[1]=top[1]=1;
    dfs2(1,0);
    build(1,1,seg[0]);
    while(m--)
    {
        scanf("%lld",&opt);
        if(opt==1)
        {
            scanf("%lld%lld",&x,&y);
            add(1,1,seg[0],seg[x],seg[x]+size[x]-1,y);
        }
        if(opt==2)
        {
            scanf("%lld%lld%lld",&x,&y,&z);
            add2(x,y,z);
        }
        if(opt==3)
        {
            scanf("%lld%lld",&x,&y);
            printf("%lld\n",find(x,y));
        }
    }
    return 0;
}

时间复杂度:O(n log(n)*log(n))

全部评论
谢谢
点赞
送花
回复
分享
发布于 2019-04-08 12:32

相关推荐

点赞 评论 收藏
转发
3 收藏 评论
分享
牛客网
牛客企业服务