Codeforces Round #406 (Div. 2) ABCDE

16 篇文章 0 订阅
9 篇文章 0 订阅

题目链接

大都是经典的套路题,下面我没做太多详细的叙述,不懂的留言就可以。

A:暴力跑一遍就可以了

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+10;
int neg[maxn],pos[maxn];
int main()
{
    int n,k,t;
    while(cin>>n>>k)
    {
        bool ans=true;
        memset(neg,0,sizeof(neg));
        memset(pos,0,sizeof(pos));
        for(int m=1;m<=k;m++)
        {
            bool flag=false;
            cin>>n;
            while(n--)
            {
                cin>>t;
                if(t<0)
                {
                    if(pos[-t]==m) flag=true;
                    else neg[-t]=m;
                }
                else if(neg[t]==m) flag=true;
                else pos[t]=m;
            }
            if(!flag) ans=false;
        }
        if(!ans) puts("YES");
        else puts("NO");
    }
}

B: 水题,每一行如果出现x,就必须有-x,bool数组判一下就过了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+10;
int neg[maxn],pos[maxn];
int main()
{
    int n,k,t;
    while(cin>>n>>k)
    {
        bool ans=true;
        memset(neg,0,sizeof(neg));
        memset(pos,0,sizeof(pos));
        for(int m=1;m<=k;m++)
        {
            bool flag=false;
            cin>>n;
            while(n--)
            {
                cin>>t;
                if(t<0)
                {
                    if(pos[-t]==m) flag=true;
                    else neg[-t]=m;
                }
                else if(neg[t]==m) flag=true;
                else pos[t]=m;
            }
            if(!flag) ans=false;
        }
        if(!ans) puts("YES");
        else puts("NO");
    }
}

C: 简单的博弈,广搜一下,把能确定胜负的点放进队列,最后不能确定胜负的就是平局
#include<bits/stdc++.h>
using namespace std;
struct Node
{
    int p;
    bool ifwin;
    bool flag;
    Node(int _p=0,bool _ifwin=0,bool _flag=0):p(_p),ifwin(_ifwin),flag(_flag){}
};
const int maxn=1e4+10;
int a,b;
int astep[maxn],bstep[maxn];
int apd[maxn],bpd[maxn];
int acnt[maxn],bcnt[maxn];
int main()
{
    int n,step;
    while(~scanf("%d",&n))
    {
        memset(acnt,0,sizeof(acnt));
        memset(bcnt,0,sizeof(bcnt));
        memset(apd,-1,sizeof(apd));
        memset(bpd,-1,sizeof(bpd));
        scanf("%d",&a);
        for(int i=0;i<a;i++) scanf("%d",&step),astep[i]=step;
        scanf("%d",&b);
        for(int i=0;i<b;i++) scanf("%d",&step),bstep[i]=step;
        queue<Node>Q;
        apd[0]=bpd[0]=0;
        Q.push(Node(0,0,1));
        Q.push(Node(0,0,0));
        while(!Q.empty())
        {
            Node head=Q.front();
            Q.pop();
            if(head.flag)
            {
                for(int i=0;i<b;i++)
                {
                    int lst=((head.p-bstep[i])%n+n)%n;
                    if(~bpd[lst]) continue;
                    if(!head.ifwin)
                    {
                        bpd[lst]=1;
                        Q.push(Node(lst,1,!head.flag));
                        continue;
                    }
                    else bcnt[lst]++;
                    if(bcnt[lst]==b)
                    {
                        bpd[lst]=0;
                        Q.push(Node(lst,0,!head.flag));
                    }
                }
            }
            else
            {
                for(int i=0;i<a;i++)
                {
                    int lst=((head.p-astep[i])%n+n)%n;
                    if(~apd[lst]) continue;
                    if(!head.ifwin)
                    {
                        apd[lst]=1;
                        Q.push(Node(lst,1,!head.flag));
                        continue;
                    }
                    else acnt[lst]++;
                    if(acnt[lst]==a)
                    {
                        apd[lst]=0;
                        Q.push(Node(lst,0,!head.flag));
                    }
                }
            }
        }
        for(int i=1;i<n;i++)
        {
            if(i>1) printf(" ");
            if(apd[i]==1) printf("Win");
            else if(apd[i]==0) printf("Lose");
            else printf("Loop");
        }
        printf("\n");
        for(int i=1;i<n;i++)
        {
            if(i>1) printf(" ");
            if(bpd[i]==1) printf("Win");
            else if(bpd[i]==0) printf("Lose");
            else printf("Loop");
        }
        printf("\n");
    }
}

D:这个题一开始我也没思路,然后在一Dalao的指点下才知道线段树优化建边这东西,看了一下,然后就过了。不过第一次写,代码写的好SB。

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
typedef long long LL;
const LL INF=1e17+10;
bool book[maxn<<4];
LL dis[maxn<<4];
int head[maxn<<2],tot,n,q,s,id,vis1[maxn<<1],vis2[maxn<<1];
struct Node
{
    int u,v,w,next;
    Node(int _u=0,int _v=0,int _w=0,int _next=0):u(_u),v(_v),w(_w),next(_next){}
}edges[maxn<<4];
struct node
{
    int v;
    LL d;
    node(int _v=0,LL _d=0):v(_v),d(_d){}
    bool operator < (const node& x)const
    {
        return d>x.d;
    }
};
void addedge(int u,int v,int w)
{
    //printf("addedge-> u:%d v:%d w:%d\n",u,v,w);
    edges[tot]=Node(u,v,w,head[u]);
    head[u]=tot++;
}
void buildtree1(int rt,int l,int r)//edges links from up to down which weight are 0
{
    if(vis1[rt]==0) vis1[rt]=++id;
    if(l==r)
    {
        addedge(vis1[rt],l,0);
        return;
    }
    int mid=(l+r)>>1,lson=rt<<1,rson=rt<<1|1;
    buildtree1(lson,l,mid);
    buildtree1(rson,mid+1,r);
    addedge(vis1[rt],vis1[lson],0);
    addedge(vis1[rt],vis1[rson],0);
}
void buildtree2(int rt,int l,int r)
{
    if(vis2[rt]==0) vis2[rt]=++id;
    if(l==r)
    {
        addedge(l,vis2[rt],0);
        return;
    }
    int mid=(l+r)>>1,lson=rt<<1,rson=rt<<1|1;
    buildtree2(lson,l,mid);
    buildtree2(rson,mid+1,r);
    addedge(vis2[lson],vis2[rt],0);//down to up - weight 0
    addedge(vis2[rson],vis2[rt],0);//down to up - weight 0
}
void addedge2(int u,int rt,int l,int r,int ql,int qr,int w)
{
    if(l>qr||r<ql) return;
    if(ql<=l&&r<=qr)
    {
        addedge(vis2[rt],u,w);
        return;
    }
    int mid=(l+r)>>1,lson=rt<<1,rson=rt<<1|1;
    addedge2(u,lson,l,mid,ql,qr,w);
    addedge2(u,rson,mid+1,r,ql,qr,w);
}
void addedge1(int u,int rt,int l,int r,int ql,int qr,int w)
{
    if(l>qr||r<ql) return;
    if(ql<=l&&r<=qr)
    {
        //cout<<1<<endl;
        //cout<<rt<<" "<<l<<" "<<r<<endl;
        addedge(u,vis1[rt],w);
        return;
    }
    int mid=(l+r)>>1,lson=rt<<1,rson=rt<<1|1;
    addedge1(u,lson,l,mid,ql,qr,w);
    addedge1(u,rson,mid+1,r,ql,qr,w);
}
void init()
{
    id=n;
    tot=0;
    memset(vis1,0,sizeof(vis1));
    memset(vis2,0,sizeof(vis2));
    memset(book,false,sizeof(book));
    memset(head,-1,sizeof(head));
    buildtree1(1,1,n);
    buildtree2(1,1,n);
}
void dijkstra()
{
    priority_queue<node>Q;
    for(int i=0;i<=9*n;i++)
    {
        //addedge(i,i,0);
        dis[i]=INF;
    }
    dis[s]=0;
    Q.push(node(s,0));
    while(!Q.empty())
    {
        node a=Q.top();
        Q.pop();
        int u=a.v;
        if(book[u]) continue;
        book[u]=true;
        //cout<<"u:"<<u<<endl;
        for(int i=head[u];~i;i=edges[i].next)
        {
            int v=edges[i].v,w=edges[i].w;
            //cout<<"v:"<<v<<" w:"<<w<<endl;
            if(dis[u]+w<dis[v])
            {
                dis[v]=dis[u]+w;
                if(!book[v]) Q.push(node(v,dis[v]));
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(dis[i]==INF) dis[i]=-1;
        if(i==1) cout<<dis[i];
        else cout<<" "<<dis[i];
    }
    puts("");
}
int main()
{
    int op,u,v,w,l,r;
    while(~scanf("%d%d%d",&n,&q,&s))
    {
        init();
        while(q--)
        {
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d%d%d",&u,&v,&w);
                addedge(u,v,w);
                // u -> f1(v,v)
            }
            else if(op==2)
            {
                scanf("%d%d%d%d",&u,&l,&r,&w);
                addedge1(u,1,1,n,l,r,w);
                // u -> f1(l,r)
            }
            else
            {
                scanf("%d%d%d%d",&u,&l,&r,&w);
                addedge2(u,1,1,n,l,r,w);
                // f2(l,r) -> u
            }
        }
        dijkstra();
    }
}

E:容易想到贪心,又因为涉及到区间不同数的个数很容易就想到主席树+二分,这样是O(n(logn)^3) 没试过(也许就过了呢),常见优化成主席树上的二分就是O(n(logn)^2)。为什么E题感觉比CD还水...

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,tot,c[maxn*100],lson[maxn*100],rson[maxn*100],T[maxn],a[maxn];
map<int,int>mp;
void init()
{
    tot=0;
    mp.clear();
}
int buildtree(int l,int r)
{
    int root=tot++;
    c[root]=0;
    if(l!=r)
    {
        int mid=(l+r)>>1;
        lson[root]=buildtree(l,mid);
        rson[root]=buildtree(mid+1,r);
    }
    return root;
}
int update(int root,int pos,int val)
{
    int newroot=tot++,tmp=newroot;
    int l=1,r=n;
    c[newroot]=c[root]+val;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(pos<=mid)
        {
            rson[newroot]=rson[root],lson[newroot]=tot++;
            newroot=lson[newroot],root=lson[root];
            r=mid;
        }
        else
        {
            lson[newroot]=lson[root],rson[newroot]=tot++;
            newroot=rson[newroot],root=rson[root];
            l=mid+1;
        }
        c[newroot]=c[root]+val;
    }
    return tmp;
}

void updatetree()
{
    T[n+1]=buildtree(1,n);
    for(int i=n;i>=1;i--)
    {
        if(mp.find(a[i])==mp.end()) T[i]=update(T[i+1],i,1);
        else
        {
            int tmp=update(T[i+1],mp[a[i]],-1);
            T[i]=update(tmp,i,1);
        }
        mp[a[i]]=i;
    }
}
int query(int root,int l,int r,int val)
{
	if(c[root]<=val) return r;
	if(l==r) return l-1;
	int mid=(l+r)>>1;
    if (c[lson[root]]<=val) return query(rson[root],mid+1,r,val-c[lson[root]]);  
    else return query(lson[root],l,mid,val);  
}
int main()
{
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        updatetree();
        for(int k=1;k<=n;k++)
        {
            int tk=1,ans=0,p;
            while(tk<=n)
            {
               int lst=query(T[tk],1,n,k);
               tk=lst+1;
               ans++;
            }
            if(k==1) printf("%d",ans);
            else printf(" %d",ans);
        }
        puts("");
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值