zoukankan      html  css  js  c++  java
  • Gym.101908 Brazil Subregional Programming Contest(寒假自训第六场)

    这几天睡眠时间都不太够,室友晚上太会折腾了,感觉有点累,所以昨天的题解也没写,看晚上能不能补起来。

    B . Marbles

    题意:给定N组数(xi,yi),玩家轮流操作,每次玩家可以选择其中一组对其操作,可以把它减去一个数,或同时减去一个数,当玩家操作后出现了(0,0)则胜利。

    思路:注意这里是出现(0,0)胜,而不是全都是(0,0)胜,所以我们不能简单的球sg,最后异或得到答案。

    但是我们转化一下,如果玩家面对的全是(1,2) 或(2,1),则他胜利,那么我们可以以这两个状态为起点得到sg函数,就转化为了nim博弈。 当然,前提是没有xi==yi的情况。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=210;
    int sg[maxn][maxn],vis[maxn];
    void getsg()
    {
        rep(i,1,100)
         rep(j,1,100){
             if(i==j) continue;
             memset(vis,0,sizeof(vis));
             rep(k,1,min(i-1,j-1)) vis[sg[i-k][j-k]]=1;
             rep(k,1,i-1) if(i-k!=j) vis[sg[i-k][j]]=1;
             rep(k,1,j-1) if(i!=j-k) vis[sg[i][j-k]]=1;
             rep(k,0,10000) if(!vis[k]){ sg[i][j]=k; break; }
        }
    }
    int main()
    {
        int N,F=0,x,y,sum=0;
        getsg();
        scanf("%d",&N);
        rep(i,1,N){
            scanf("%d%d",&x,&y);
            sum^=sg[x][y];
            if(x==y) F=1;
        }
        if(F||sum) puts("Y");
        else puts("N");
        return 0;
    }
    View Code

    C .Pizza Cutter

    题意:对于一个匹萨,限制横着切N刀,竖着切M刀,问最后披萨被分为了多少块。 保证不存在超过三刀相交在一点的情况,以及在角上相交的情况。

    思路:我们发现,一刀的贡献是与它相交的直线数+1。 横线和竖线的交点=N*M。 横线和横线的交点=逆序对数。竖线与竖线一样。

    所以求两次逆序对即可。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    struct in{
        int x,y;
        bool friend operator <(in w,in v) { return w.x<v.x;}
    }s[maxn];
    int sum[maxn],b[maxn],tot;
    void add(int a,int N){
        for(int i=a;i<=N;i+=(-i)&i) sum[i]++;
    }
    int query(int a){
        int res=0; for(int i=a;i;i-=(-i)&i) res+=sum[i];
        return res;
    }
    ll get(int N)
    {
        sort(s+1,s+N+1); ll res=0;
        rep(i,1,N) sum[i]=0,b[i]=s[i].y;
        sort(b+1,b+N+1); tot=unique(b+1,b+N+1)-(b+1);
        rep(i,1,N) s[i].y=lower_bound(b+1,b+N+1,s[i].y)-b;
        for(int i=N;i>=1;i--){
            res+=query(s[i].y);
            add(s[i].y,N);
        }return res;
    }
    int main()
    {
        int N,M; ll ans=0;
        scanf("%d%d",&N,&M); scanf("%d%d",&N,&M);
        rep(i,1,N) scanf("%d%d",&s[i].x,&s[i].y);
        ans=get(N);
        rep(i,1,M) scanf("%d%d",&s[i].x,&s[i].y);
        ans+=get(M);
        ans+=(ll)N*M+N+M+1;
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    D .Unraveling Monty Hall

    题意:统计不是1的个数。

    思路:水题,就是题面太长。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    int main()
    {
        int N,x,ans=0;
        scanf("%d",&N);
        rep(i,1,N) scanf("%d",&x),ans+=(x!=1);
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    E .Enigma

    题意:给定字符串S,T,让T去匹配S,问有多少个匹配没有相同的字符。

    思路:模拟。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1000010;
    char c[maxn],b[maxn];
    int main()
    {
        int N,M,ans=0;
        scanf("%s%s",c+1,b+1);
        N=strlen(c+1); M=strlen(b+1);
        rep(i,1,N-M+1) {
            bool F=true;
            rep(j,1,M) if(b[j]==c[i+j-1]) F=false;
            ans+=(F);
        }
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    F .Music Festival

    题意:有N个舞台(N<10),第i个舞台有Mi首歌(M总和<1000),给出每首歌的起始时间s,和终止时间t,以及价值val; 我们听完一首歌可以任意瞬移到另外的舞台,即不考虑时间边界。现在让你选择一种方案,使得每个舞台都至少听了一首歌,求最大价值。

    思路:区间最值更新答案的,我们可以用线段树或者单调队列更新答案。这里用了线段树。 先离散化时间(2*N个),然后对于所有的节目,按起始时间排序(终止时间排序效果也一样),然后每次查询[1,s]的最大值,然后用结果去更新t点的值。 复杂度O(N^2*logN)。记录一个前缀最大值复杂度是O(N^2)的。

    线段树:

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define rep2(i,a,b) for(int i=a;i>=b;i--)
    using namespace std;
    const int maxn=1024;
    int dp[maxn][maxn],b[maxn<<1],cnt; bitset<maxn>S[maxn];
    struct in{
        int s,t,val,id;
        bool friend operator <(in w,in v){
            return w.s<v.s;
        }
    }s[maxn];
    struct Tree{
        int Mx[maxn<<3];
        void update(int Now,int L,int R,int pos,int val)
        {
            Mx[Now]=max(Mx[Now],val);
            if(L==R) return ; int Mid=(L+R)>>1;
            if(pos<=Mid) update(Now<<1,L,Mid,pos,val);
            if(pos>Mid) update(Now<<1|1,Mid+1,R,pos,val);
        }
        int query(int Now,int L,int R,int l,int r)
        {
            if(l<=L&&r>=R) return Mx[Now];
            int Mid=(L+R)>>1,res=0;
            if(l<=Mid) res=max(res,query(Now<<1,L,Mid,l,r));
            if(r>Mid) res=max(res,query(Now<<1|1,Mid+1,R,l,r));
            return res;
        }
    }T[1024];
    int main()
    {
        int N,M,tot=0,ans=0;
        scanf("%d",&N);
        rep(i,0,N-1){
            scanf("%d",&M);
            rep(j,1,M){
                tot++;
                scanf("%d%d%d",&s[tot].s,&s[tot].t,&s[tot].val);
                s[tot].id=i; b[++cnt]=s[tot].s; b[++cnt]=s[tot].t;
            }
        }
        sort(b+1,b+cnt+1); cnt=unique(b+1,b+cnt+1)-(b+1);
        sort(s+1,s+tot+1); M=(1<<N)-1;
        rep(i,1,tot) s[i].s=lower_bound(b+1,b+cnt+1,s[i].s)-b;
        rep(i,1,tot) s[i].t=lower_bound(b+1,b+cnt+1,s[i].t)-b;
        rep(i,1,tot) {
            dp[i][1<<s[i].id]=s[i].val;
            rep(j,1,M){
                if(T[j].Mx[1]==0) continue;
                int Mx=T[j].query(1,1,cnt,1,s[i].s);
                if(Mx!=0) dp[i][j|(1<<s[i].id)]=max(dp[i][j|(1<<s[i].id)],Mx+s[i].val);
            }
            rep(j,1,M) {
                if(dp[i][j]) T[j].update(1,1,cnt,s[i].t,dp[i][j]);
            }
            ans=max(ans,dp[i][M]);
        }
        if(ans==0) ans=-1;
        printf("%d
    ",ans);
        return 0;
    }
    View Code

     前缀最大值: (数组开小wa了一发)

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define rep2(i,a,b) for(int i=a;i>=b;i--)
    using namespace std;
    const int maxn=1024;
    int dp[maxn][maxn],pre[maxn][maxn<<1],b[maxn<<1],cnt;
    struct in{
        int s,t,val,id;
        bool friend operator <(in w,in v){
            return w.s<v.s;
        }
    }s[maxn];
    int main()
    {
        int N,M,tot=0,ans=0;
        scanf("%d",&N);
        rep(i,0,N-1){
            scanf("%d",&M);
            rep(j,1,M){
                tot++;
                scanf("%d%d%d",&s[tot].s,&s[tot].t,&s[tot].val);
                s[tot].id=i; b[++cnt]=s[tot].s; b[++cnt]=s[tot].t;
            }
        }
        sort(b+1,b+cnt+1); cnt=unique(b+1,b+cnt+1)-(b+1);
        sort(s+1,s+tot+1); M=(1<<N)-1;
        rep(i,1,tot) s[i].s=lower_bound(b+1,b+cnt+1,s[i].s)-b;
        rep(i,1,tot) s[i].t=lower_bound(b+1,b+cnt+1,s[i].t)-b;
        int pos=1;
        rep(i,1,tot) {
            while(pos<=s[i].s){ //更新前缀最大值
                rep(j,1,M) pre[j][pos]=max(pre[j][pos-1],pre[j][pos]);
                pos++;
            }
            int t=1<<s[i].id; dp[i][t]=s[i].val;
            pre[t][s[i].t]=max(pre[t][s[i].t],s[i].val);
            rep(j,1,M)
              if(pre[j][s[i].s]) 
                dp[i][j|t]=max(dp[i][j|t],pre[j][s[i].s]+s[i].val);
            rep(j,1,M)
              if(dp[i][j]) pre[j][s[i].t]=max(pre[j][s[i].t],dp[i][j]);
            ans=max(ans,dp[i][M]);
        }
        if(ans==0) ans=-1;
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    G .Gasoline

    题意:给定N个加油站,M个油田(<1000),以及加油站的需要量,油田的供给量,以及C条带权道路(C<20000),现在让你最小化最大运输时间。

    思路:二分+最大流。复杂度N*sqrt(C)*logC;

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2000010;
    const int inf=2000000000;
    int N,M,P,R,C,S,T;
    int Laxt[maxn],Next[maxn],To[maxn],Cap[maxn],cnt;
    int dis[maxn],vd[maxn],sum;
    int a[maxn],b[maxn]; struct in{ int x,y,z; }s[maxn];
    bool cmp(in w,in v){ return w.z<v.z;}
    void add(int u,int v,int c)
    {
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Cap[cnt]=c;
        Next[++cnt]=Laxt[v]; Laxt[v]=cnt; To[cnt]=u; Cap[cnt]=0;
    }
    int sap(int u,int flow)
    {
        if(u==T||flow==0) return flow;
        int tmp,delta=0;
        for(int i=Laxt[u];i;i=Next[i]){
            int v=To[i]; if(dis[u]==dis[v]+1&&Cap[i]){
                tmp=sap(v,min(Cap[i],flow-delta));
                Cap[i]-=tmp; Cap[i^1]+=tmp; delta+=tmp;
                if(dis[S]>=T||delta==flow) return delta;
            }
        }
        vd[dis[u]]--;  if(!vd[dis[u]]) dis[S]=T;
        vd[++dis[u]]++;
        return delta;
    }
    bool check(int Mid)
    {
       rep(i,S,T) Laxt[i]=dis[i]=vd[i]=0; cnt=1;
       rep(i,1,Mid) add(s[i].y,R+s[i].x,inf);
       rep(i,1,R) add(S,i,b[i]);
       rep(i,1,P) add(R+i,T,a[i]);
       int res=0;
       while(dis[S]<T) res+=sap(S,inf);
       return res==sum;
    }
    int main()
    {
        scanf("%d%d%d",&P,&R,&C); S=0; T=P+R+1;
        rep(i,1,P) scanf("%d",&a[i]),sum+=a[i];
        rep(i,1,R) scanf("%d",&b[i]);
        rep(i,1,C) scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].z);
        sort(s+1,s+C+1,cmp);
        int ans=-1,L=1,R=C,Mid;
        while(L<=R){
            Mid=(L+R)>>1;
            if(check(Mid)) ans=Mid,R=Mid-1;
            else L=Mid+1;
        }
        if(ans==-1) puts("-1");
        else printf("%d
    ",s[ans].z);
        return 0;
    }
    View Code

    K .Kepler

    题意:给定n个包含了原点的圆(-25.0<=x,y<=25.0, 1<=r<=2e5),而且满足没有两个以上的圆在一点相交,问这些圆一共有多少个交点,如果交点数>2*N,输出greater。

    思路:首先,我们提炼出关键,他们都包含了原点,说明他们之间只有包含和相交关系,而且每次相交贡献两个交点,而且发现这些圆的圆心范围比较小,而半径又不是很小,所以我们可以提炼出一些包含关系,这些包含关系的在比较坏的情况下,最外层也就50*50/(2*2)这么多吧,然后对于每组包含关系,我们都从大到小保存起来。 然后我们就可以dfs看这组与外面的圆的相交个数了。     按半径从小到大加入一些圆,然后去验证这些包含关系有多少个相交即可。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=200010;
    struct in{ double x,y,r;}s[maxn];
    bool cmp(in w,in v){ return w.r<v.r; }
    int ans,N,Laxt[maxn],Next[maxn],To[maxn],cnt;
    set<int>S; set<int>::iterator it,tmp;
    const double eps=1e-8;
    void add(int u,int v){
        Next[++cnt]=Laxt[u];  Laxt[u]=cnt; To[cnt]=v;
    }
    bool check(in A,in B)
    {
        return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)<=(A.r-B.r)*(A.r-B.r);
    }
    void dfs(int u,int p)
    {
        if(check(s[u],s[p])) return;
        ans++;
        if(ans>N) return ;
        for(int i=Laxt[u];i;i=Next[i]) dfs(To[i],p);
    }
    int main()
    {
        scanf("%d",&N);
        rep(i,1,N) scanf("%lf%lf%lf",&s[i].x,&s[i].y,&s[i].r);
        sort(s+1,s+N+1,cmp);
        rep(i,1,N){
            for(it=S.begin();it!=S.end();){
                if(check(s[i],s[*it])){
                    add(i,*it);tmp=it;
                    it++;S.erase(tmp);
                }
                else dfs(*it,i),it++;
            }
            S.insert(i);
        }
        if(ans>N) puts("greater");
        else printf("%d
    ",ans*2);
        return 0;
    }
    View Code

    I .Switches

    题意:给定N个灯,以及开始状态。M个开关集合,每次使用一个开关,这个集合的状态会改变。 现在一次按1到M个开关,即1,2,3,...M ,1, 2,... 问第几次会全部关掉。

    思路:最多两轮,模拟即可。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1010;
    int vis[maxn],L[maxn],a[maxn][maxn];
    int main()
    {
        int N,M,num,x,ans=-1;
        scanf("%d%d",&N,&M);
        scanf("%d",&num);
        rep(i,1,num)scanf("%d",&x),vis[x]=1;
        rep(i,1,N){
            scanf("%d",&L[i]);
            rep(j,1,L[i]){
                scanf("%d",&a[i][j]); x=a[i][j];
                if(vis[x]==1) vis[x]=0,num--;
                else  vis[x]=1,num++;
            }
            if(num==0&&ans==-1) ans=i;
        }
        if(ans!=-1) printf("%d
    ",ans);
        else {
            rep(i,1,N){
              rep(j,1,L[i]){
                x=a[i][j];
                if(vis[x]==1) vis[x]=0,num--;
                else  vis[x]=1,num++;
              }
             if(num==0&&ans==-1) ans=N+i;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    L .Subway Lines

    题意:给出一棵树,Q次询问两个路径的交点个数/

    思路:可以用LCA推。 也可以直接上树剖+标记。

    by,许

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+10;
    int id[maxn],dep[maxn],cnt;
    int top[maxn],size[maxn],f[maxn],son[maxn];
    vector<int>G[maxn];
    int sum[maxn*4],tag[maxn*4];
    void dfs1(int u,int fa,int deep)
    {
        size[u]=1;
        dep[u]=deep;
        f[u]=fa;
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(v==fa)continue;
            dfs1(v,u,deep+1);
            size[u]+=size[v];
            if(!son[u]||size[v]>size[son[u]])
            son[u]=v;
        }
    }
    void dfs2(int u,int root)
    {
        top[u]=root;
        id[u]=++cnt;
        if(son[u]) dfs2(son[u],root);
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(v==f[u]||v==son[u])continue;
            dfs2(v,v);
        }
    }
    /*void update(int o,int l,int r,int ql,int qr,int v)
    {
        int m=(l+r)/2,ls=o*2,rs=o*2+1;
        if(tag[o]!=-1&&l!=r)
        {
            sum[ls]=(m-l+1)*tag[o];
            sum[rs]=(r-l)*tag[o];
            tag[ls]=tag[rs]=tag[o];
            tag[o]=-1;
        }
        if(l>=ql&&r<=qr)
        {
            sum[o]=v*(r-l+1);
            tag[o]=v;
            return;
        }
        if(ql<=m)update(ls,l,m,ql,qr,v);
        if(qr>m)update(rs,m+1,r,ql,qr,v);
        sum[o]=sum[ls]+sum[rs];
    }
    int query(int o,int l,int r,int ql,int qr)
    {
        int m=(l+r)/2,ls=o*2,rs=o*2+1,res=0;
        if(tag[o]!=-1&&l!=r)
        {
            sum[ls]=(m-l+1)*tag[o];
            sum[rs]=(r-l)*tag[o];
            tag[ls]=tag[rs]=tag[o];
            tag[o]=-1;
        }
        if(sum[o]==r-l+1)
        return min(r,qr)-max(l,ql)+1;
        if(sum[o]==0)return 0;
        if(l>=ql&&r<=qr)
        return sum[o];
        if(ql<=m)res+=query(ls,l,m,ql,qr);
        if(qr>m)res+=query(rs,m+1,r,ql,qr);
        return res;
    }*/
    void update(int o,int l,int r,int ql,int qr,int v)
    {
        int m=(l+r)/2,ls=o*2,rs=o*2+1;
        if(tag[o]!=-1&&l!=r)
        {
            sum[ls]=(m-l+1)*tag[o];
            sum[rs]=(r-l)*tag[o];
            tag[ls]=tag[rs]=tag[o];
            tag[o]=-1;
        }
        if(l>=ql&&r<=qr)
        {
            sum[o]=v*(r-l+1);
            tag[o]=v;
            return;
        }
        if(ql<=m)update(ls,l,m,ql,qr,v);
        if(qr>m)update(rs,m+1,r,ql,qr,v);
        sum[o]=sum[ls]+sum[rs];
    }
    int query(int o,int l,int r,int ql,int qr)
    {
        int m=(l+r)/2,ls=o*2,rs=o*2+1,res=0;
        if(tag[o]!=-1&&l!=r)
        {
            sum[ls]=(m-l+1)*tag[o];
            sum[rs]=(r-l)*tag[o];
            tag[ls]=tag[rs]=tag[o];
            tag[o]=-1;
        }
        if(sum[o]==r-l+1)
        return min(r,qr)-max(l,ql)+1;
        if(sum[o]==0)return 0;
        if(l>=ql&&r<=qr)
        return sum[o];
        if(ql<=m)res+=query(ls,l,m,ql,qr);
        if(qr>m)res+=query(rs,m+1,r,ql,qr);
        return res;
    }
    /*void up_path(int x,int y,int z)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<top[top[y]]) swap(x,y);
            update(1,1,cnt,id[top[x]],id[x],z);
            x=f[top[x]];
        }
        if(id[x]>id[y]) swap(x,y);
        update(1,1,cnt,id[x],id[y],z);
    }*/
    int qu_path(int x,int y)
    {
        int res=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            res+=query(1,1,cnt,id[top[x]],id[x]);
            x=f[top[x]];
        }
        if(id[x]>id[y])swap(x,y);
        res+=query(1,1,cnt,id[x],id[y]);
        return res;
    }
    void up_path(int x,int y,int z)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            update(1,1,cnt,id[top[x]],id[x],z);
            x=f[top[x]];
        }
        if(id[x]>id[y])swap(x,y);
        update(1,1,cnt,id[x],id[y],z);
    }
    /*int qu_path(int x,int y)
    {
        int ans=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            ans+=query(1,1,cnt,id[top[x]],id[x]);
            x=f[top[x]];
        }
        if(id[x]>id[y])swap(x,y);
        ans+=query(1,1,cnt,id[x],id[y]);
        return ans;
    }*/
    int main()
    {
        int n,u,v,a,b,c,d,q;
        scanf("%d%d",&n,&q);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        memset(tag,-1,sizeof(tag));
        dfs1(1,0,1);
        dfs2(1,1);
        while(q--)
        {
            scanf("%d%d%d%d",&a,&b,&c,&d);
            up_path(a,b,1);
            printf("%d
    ",qu_path(c,d));
            up_path(a,b,0);
        }
    }
    View Code
  • 相关阅读:
    第二次作业
    第五次作业
    第四次作业
    第三次作业
    第二次作业
    第三次作业
    第二次作业
    第二次作业
    gravity
    card
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10350608.html
Copyright © 2011-2022 走看看