洛谷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;
}
原文地址:https://www.cnblogs.com/FallDream/p/luogu4.html