• 洛谷4月月赛R1 Happy Poppin' Party Train


    来自FallDream的博客,未经允许,请勿转载,谢谢。


    听学长说的就来玩一玩,随便乱打打  没想到一堆人被取消了成绩,莫名混了个Rank3

    还有第一题数据肯定是有问题

    ------------------------------------------

    T1 邦邦的大合唱站队/签到题

    N个偶像排成一列,他们来自M个不同的乐队。每个团队至少有一个偶像。

    现在要求重新安排队列,使来自同一乐队的偶像连续的站在一起。重新安排的办法是,让若干偶像出列(剩下的偶像不动),然后让出列的偶像一个个归队到原来的空位,归队的位置任意。

    请问最少让多少偶像出列?  n<=100000 m<=20

    题解:这个应该很好想到状压dp吧 用f[i]表示选的乐队的状态是i的最小出列人数,那么枚举一个乐队转移一下就好了,至于算要出列多少人,可以差分一下。复杂度$m*2^{m}$

    /*然后我来教你们怎么AC

    首先,快速读入统统删掉,加了快速读入只有20分,其它全是T。

    然后呢,虽然我们只需要差分数组,但是呢,必须把ai读入到数组里,不能读到变量。读到变量只有70,不信自己试试。大概是数据有问题,数组会溢出。

    最后呢,写写代码,cin或者scanf随意。*/

    数据已经修正了,没毛病。我貌似被这个从100坑到了60

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define MN 200000
    #define MM 30
    #define int long long
    using namespace std;
    int X;
    //inline int read()
    //{
     //   cin>>X;return X;
    /*    int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;*/
    //}
    
    int n,m,s[MN+5];
    int f[MM+2][MN+5],size[MN+5],tot[(1<<21)+5],F[(1<<21)+5];
    
    main()
    {
    //    freopen("sb.in","r",stdin);
        cin>>n>>m;
        for(register int i=1;i<=n;i++) 
        {
              cin>>s[i];   
            for(register int j=1;j<=m;j++) f[j][i]=f[j][i-1];
            ++f[s[i]][i];++size[s[i]];
        }
        for(register int i=0;i<1<<m;i++)
            for(register int j=0;j<m;j++)
                if((1<<j)&i) tot[i]+=size[j+1];
        memset(F,42,sizeof(F));F[0]=0;
        for(register int i=1;i<1<<m;i++)
            for(register int j=1;j<=m;j++)
                if(i&(1<<(j-1)))
                    F[i]=min(F[i],F[i^(1<<(j-1))]+size[j]-f[j][tot[i]]+f[j][tot[i]-size[j]]);
        printf("%lld
    ",F[(1<<m)-1]);
        return 0;
    }

    B.开心派对小火车

    Aqours铁路公司旗下有N个站,编号1,2,..,N。

    有各停(各站停车)电车特急电车两种。特急车会在si..sm,一共M个车站停车。

    相邻的两站(即编号为i的车站和编号为的车站,而不是特急电车停车的相邻的两站)之间,各停电车要运行A分钟,特急需要B分钟。我们认为列车一直匀速运行,不考虑停车和加减速。

    现在要加一种快速电车,要求其停站覆盖所有的特急电车的停站,而相邻的两站要运行C分钟。为了要快,决定刚好停K个站(k>m,包括特急的所有车站)。如果一个站可以停多种电车,那么旅客可以在这一站换乘。不过只能向前坐车,不能往回坐。

    你需要设计一种快速列车的设站方案,要求旅客在T分钟**乘车时间(等车和换乘时间不计)**内,可以从1号站到尽可能多数量的站。你只需要告知能有几站可以达到。

    n,a,b,c<=10^9,  m,k<=3000 ,T<=10^18

    题解:答案肯定是你做B车到一个站,转C车,然后做A车,所以对于每一个段,你都右端点贪心,也就是每次选择目前能到的点建站。然后把这些塞到一个堆里,每次取出最大,重新算一下塞回去就行了。

    复杂度只有klogm,不是很懂。

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #define pa pair<int,int> 
    #define mp(x,y) make_pair(x,y)
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,m,k,a,b,c,s[3005],r[3005];
    ll ans,T,t[3005];
    priority_queue<pa>q;
    
    void push(int x)
    {
        if(r[x]==s[x+1]-1) return;++r[x];
        ll time=(T-t[x]-1LL*(r[x]-s[x])*c);
        if(time<0)return;
        int R=(int)min(1LL*(s[x+1]-1),r[x]+time/a);
        q.push(mp(R-r[x]+1,x)); 
        r[x]=R;
    }
    
    int main()
    {
        n=read();m=read();k=read();a=read();b=read();c=read();
        scanf("%lld",&T);
        for(int i=1;i<=m;i++) s[i]=read();s[m+1]=n+1;
        for(int i=1;i<=m;i++)
        {
              t[i]=1LL*b*(s[i]-s[1]);
              if(t[i]>T) continue; 
            r[i]=(int)min(1LL*s[i+1]-1,s[i]+(T-t[i])/a);
              ans+=r[i]-s[i]+1;
        }
        for(int i=1;i<m;i++) if(t[i]<=T)push(i);else break;
        for(int i=1;i<=k-m&&!q.empty();i++)
        {
            pa x=q.top();q.pop();
            ans+=x.first;push(x.second);
        }
        printf("%lld
    ",ans-1);
        return 0;
    }

    C.什么?这场比赛有C题?

    D.Bushiroad的偶像派对

    Bushiroad的派对有N个校园偶像团体,可能来自编号1-N的学校。每个学校可能有多个团体参加,也有可能没有团体参加。在所有的团体都演出完后,进行人气投票。

    我们已经掌握分别了中场时和结束时的两张人气排行表。给出排行表从人气高到低排序,并给出每个组的学校编号(你却不知道具体是哪个团体)

    可是,结束时的表是不太准确的。因为基于这样的一个事实:某个团体的结束时的人气不会低于中场的人气,而且每个团体的学校不会改变。结束的表产生一些矛盾。

    负责统计的人为了不想背锅,希望尽可能少修改结束时的排行表的某些团体的学校(人气值不能改),使其不矛盾,请问至少要修改多少个呢?

    题解:现场只会yy了一个费用流,只过了70%的点。

    大概就是把每个结束时的人气拆成两个点,表示相同学校和不同学校,然后限制这两个点只能流1,两个点都向比他大的下一个点连边(第二个点往同颜色连边)。每个中场的点和第一个大等他的随意学校和相同学校(如果有)连边,和不同学校的点的连边设置费用1,跑一次费用流。这个能通过70%,也就是5000的数据

    正解:贪心

    从小到大拿结束时的人气去匹配。显然如果能匹配到相同学校的一定最优,那么只要能判断即可。这个可以通过线段树维护  每个点在他之前还有几个点可以被选  的最小值实现

    费用流70%

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    #define S 0
    #define MAXN 200000 
    #define INF 200000000
    #define getchar() (SS==TT&&(TT=(SS=B)+fread(B,1,1<<15,stdin),SS==TT)?0:(*SS++))
    using namespace std;
    char B[1<<15],*SS=B,*TT=B;
    inline int read()
    {
        int x=0;char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x;
    }
    
    int ans=0,pi=0,T,d[MAXN*4+5],head[MAXN*4+5],n,m,cnt=1,t[MAXN+5],p[MAXN+5],t2[MAXN+5],p2[MAXN+5];
    bool mark[MAXN*4+5];
    struct edge{
        int w,to,next,c;
    }e[4000000];
    vector<int> v[MAXN+5]; 
    deque<int> q;
     
    void insw(int f,int t,int w,int c)
    {
        e[++cnt].next=head[f];head[f]=cnt;
        e[cnt].to=t; e[cnt].w=w;e[cnt].c=c;
    }
     
    void ins(int f,int t,int w,int c){insw(f,t,w,c);insw(t,f,0,-c);}
     
    bool modlabel()
    {
        q.push_back(T);
        for(int i=0;i<=T;i++) d[i]=INF;d[T]=0;
        while(!q.empty())
        {
            int u=q.front();q.pop_front();
            for(int i=head[u];i;i=e[i].next)
                if(e[i^1].w&&d[u]+e[i^1].c<d[e[i].to])
                {
                    d[e[i].to]=d[u]+e[i^1].c;
                    if(d[e[i].to]<=d[q.size()?q.front():0])
                           q.push_front(e[i].to);
                    else
                        q.push_back(e[i].to);
                }    
        }
        for(int i=0;i<=T;i++)
            for(int j=head[i];j;j=e[j].next)
                e[j].c+=d[e[j].to]-d[i];
        pi+=d[S];
        return d[S]!=INF;
    }
     
    int dfs(int x,int f)
    {
        if(x==T) return ans+=pi*f,f;
        mark[x]=1;
        int used=0,nown;
        for(int i=head[x];i;i=e[i].next)
            if(!mark[e[i].to]&&!e[i].c&&e[i].w)
            {
                nown=dfs(e[i].to,min(f-used,e[i].w));
                e[i].w-=nown;e[i^1].w+=nown;
                used+=nown;if(used==f) return f;
            }
        return used;
    }
     
    int get(int x)
    {
        int l=1,r=n,mid,ans;
        while(l<=r)
        {
            mid=l+r>>1;
            if(p2[mid]<x) r=mid-1;
            else ans=mid,l=mid+1;
        }
        return ans;
    }
    
    int get2(int x,int c)
    {
         int l=0,r=v[c].size()-1,mid,ans=-1;
         while(l<=r)
         {
             mid=l+r>>1;
             if(p2[v[c][mid]]<x) r=mid-1;
             else ans=v[c][mid],l=mid+1;
         }
         return ans;
    } 
     
    int main()
    {
        n=read();T=n*4+1;
        for(register int i=1;i<=n;i++) t[i]=read(),p[i]=read();
        for(register int i=1;i<=n;i++)
        {
            t2[i]=read();p2[i]=read();
            v[t2[i]].push_back(i);
        }    
        for(register int i=1;i<=n;i++) ins(S,i,1,0),ins(i+3*n,T,1,0);
        for(register int i=1;i<=n;i++)
        {
            int x=get(p[i]),y=get2(p[i],t[i]);
            ins(i,x+n,1,1);if(y!=-1)ins(i,y+2*n,1,0);
            if(i<n) ins(i+n+1,i+n,INF,0);
            ins(i+n,i+3*n,1,0);ins(i+2*n,i+3*n,1,0);
        }
        for(register int i=1;i<=n;i++) for(register int j=1;j<v[i].size();j++)
            ins(v[i][j]+2*n,v[i][j-1]+2*n,INF,0);
        while(modlabel()) 
            do memset(mark,0,sizeof(bool)*(T+1));
            while(dfs(S,INF));
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    贪心

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #define INF 200000000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,ans,Last[400005];
    vector<int> v[200005];
    struct Node{int l,r,x,val;}T[1600005];
    struct P{int kind,t,x,last;
        bool operator <(const P&y)const{return x==y.x?kind>y.kind:x<y.x;}
    }p[400005];
    
    void pushdown(int x)
    {
        int ad=T[x].val,l=x<<1,r=x<<1|1;
        T[x].val=0;
        T[l].val+=ad;T[r].val+=ad;
        T[l].x+=ad;T[r].x+=ad;
    }
    
    void build(int x,int l,int r)
    {
        if((T[x].l=l)==(T[x].r=r)){ T[x].x=INF;return;}
        int mid=l+r>>1;
        build(x<<1,l,mid);build(x<<1|1,mid+1,r);
        T[x].x=min(T[x<<1].x,T[x<<1|1].x);
    }
    
    void renew(int x,int l,int r,int ad)
    {
        if(T[x].l==l&&T[x].r==r){T[x].x+=ad;T[x].val+=ad;return;}
        if(T[x].val) pushdown(x);
        int mid=T[x].l+T[x].r>>1;
        if(r<=mid) renew(x<<1,l,r,ad);
        else if(l>mid) renew(x<<1|1,l,r,ad);
        else renew(x<<1,l,mid,ad),renew(x<<1|1,mid+1,r,ad);
        T[x].x=min(T[x<<1].x,T[x<<1|1].x);
    }
    
    bool check(int from)
    {
        renew(1,from+1,n,-1);
        if(T[1].x>=0) return true;
        renew(1,from+1,n,1); return false;
    }
    
    void change(int x,int k,int ad)
    {
        if(T[x].l==T[x].r){T[x].x=ad;return;}
        if(T[x].val) pushdown(x);
        int mid=T[x].l+T[x].r>>1;
        change(x<<1|(k>mid),k,ad);
        T[x].x=min(T[x<<1].x,T[x<<1|1].x);
    }
    
    int main()
    {
        ans=n=read();
        for(int i=1;i<=n;i++)
            p[i].t=read(),p[i].x=read(),p[i].kind=1;
        for(int i=1;i<=n;i++)
            p[i+n].t=read(),p[i+n].x=read();
        for(int i=n,j=n;i;--i)    
        {
            while(j>1&&p[j+n].x<p[i].x) --j;
            p[i].last=n-j;
        }
        sort(p+1,p+n*2+1);  
        build(1,1,n);
        for(int i=1,j=1;i<=n<<1;j+=(p[i++].kind)^1)
            if(p[i].kind)
                v[p[i].t].push_back(i);
            else
            {
                if(v[p[i].t].size())
                {
                    int u=v[p[i].t][v[p[i].t].size()-1];
                    if(p[u].last==n||check(p[u].last))
                    {
                        v[p[i].t].pop_back();--ans;
                    }
                    else change(1,j,i-2*j);
                }
                else change(1,j,i-2*j);
            }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    MySQL-EXPLAIN执行计划字段解释
    MySQL-EXPLAIN执行计划Extra解释
    HTTP与HTTPS的区别
    【面试】Java中sleep和wait的区别
    Nginx之前后端分离(入门)
    玩程序 之 一 . 字符串处理工具(可通过C#脚本扩展)
    C#实现下载功能,可用于软件自动更新
    对c#剪切板Clipboard占用的问题一点解决方法
    C# 制作 仪表
    C#使用自定义字体(从文件获取)
  • 原文地址:https://www.cnblogs.com/FallDream/p/luogu4.html
Copyright © 2020-2023  润新知