zoukankan      html  css  js  c++  java
  • CERC2016 爵士之旅 Jazz Journey

    传送门(洛谷)

    题目大意

    给定$n$个位置,和一个长为$m$的序列$A$,你需要经过一条直接的边从第$A_i$个位置到第$A_{i+1}$个位置。

    每条有向边$(u,v)$分为两种,第一种可以花费$C$的代价从$u$到达$v$。

    第二种可以花费$C'$的代价从$u$到达$v$,并使得下一次从$v$到$u$的代价变为$0$。

    保证操作一定能完成。$n,mleq 3 imes 10^5$。

    题解

    考虑每两个位置之间$(a,b)$或$(b,a)$的若干次移动式独立的,不同的位置对之间互不影响。

    所以对于每一个点对$(a,b)$分开处理。

    先将这$m-1$次移动中在$(a,b)$之间的移动按照顺序拿出来构成一个$01$序列,其中$0$表示从$a$到$b$,$1$表示从$b$到$a$(不妨设$a<b$)。
    接下来可以直接贪心。

    设$A$表示直接从$a$到$b$的最小代价,设$B$表示直接从$b$到$a$的最小代价。

    设$AA$表示从$a$到$b$并使得下一次从$b$到$a$的代价为$0$的最小代价。
    设$BB$表示从$b$到$a$并使得下一次从$a$到$b$的代价为$0$的最小代价。

    若$A+Bleq min{AA,BB}$,那么每一次操作一定选择直接走,用$0,1$的数量分别乘以$A,B$即可。

    若$AA<A+Bleq BB$,那么每一次操作一定优先尽可能地将每一个$0$匹配一个位于它后面的$1$,每个最前面的$0$贪心地取后方最靠近它的$1$,这样匹配出的$1$地数量一定是最多的,那么省下来的$0$和$1$一定花费$A,B$的代价。

    $BB<A+Bleq AA$与上一情况同理。

    若$AAleq BB<A+B$,这样一定在优先将每一个$1$匹配的基础上再将这些匹配到的$1$用在最后的位置上,尽可能不让前置的$1$被消耗。然后我们再类比上一情况的方法贪心取让每一个前置的$1$取它后面最接近的,没有被消耗的$0$,这样取完后剩下的部分要以相同的方法删掉。

    $BB<AA<A+B$与上一情况同理。

    #include<bits/stdc++.h>
    #define LL long long
    #define pii pair<int,int>
    #define mp(a,b) make_pair(a,b)
    #define dw(x,y) x=min(x,y)
    #define M 300200
    #define link(a,b) nt[++tmp]=fs[a],fs[a]=tmp,kd[tmp]=b
    using namespace std;
    namespace IO{
    	const int BS=(1<<20)+5; char Buffer[BS],*HD,*TL;
    	char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;}
    	int read(){
    		int nm=0,fh=1; char cw=Getchar();
    		for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
    		for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
    		return nm*fh;
    	}
    	int gc(){
    		int cw=Getchar();
    		while(cw!='R'&&cw!='O') cw=Getchar();
    		return cw=='R';
    	}
    }using namespace IO;
    map<pii,int> P; LL ans,F[M],c[M][2][2];
    int n,m,A[M],tot,cnt,top,K[M],s[M][2],pre[M][2];
    int fs[M],kd[M],nt[M],tmp; char C[20];
    LL solve(int x){
    	dw(c[x][0][0],c[x][0][1]),dw(c[x][1][0],c[x][1][1]); 
    	LL cst=c[x][0][0]+c[x][1][0];
    	if(cst<=min(c[x][0][1],c[x][1][1]))
    		return (LL)s[top][0]*c[x][0][0]+(LL)s[top][1]*c[x][1][0];
    	if(c[x][0][1]>c[x][1][1]){
    		swap(c[x][0][1],c[x][1][1]),swap(c[x][0][0],c[x][1][0]);
    		for(int i=1;i<=top;i++) swap(s[i][0],s[i][1]),K[i]^=1;
    	}
    	for(int k=0;k<2;k++){
    		for(int i=1,now=1;i<=top;i++){
    			pre[i][k]=pre[i-1][k]; if(K[i]^k) continue;
    			while(now<i||(now<=top&&(K[now]^k^1))) now++;
    			if(now<=top) now++,pre[i][k]++;
    		}
    	} 
    	LL pos,rem=pre[top][0],t1,t2; t1=s[top][0]-rem,t2=s[top][1]-rem;
    	if(cst<=c[x][1][1]) return rem*c[x][0][1]+t1*c[x][0][0]+t2*c[x][1][0];
    	for(pos=1;pos<=top&&s[pos][1]<=s[top][1]-rem;pos++); pos--;
    	LL num=min(s[top][0]-rem,(LL)pre[pos][1]);
    	t1=s[top][0]-rem-num,t2=s[top][1]-rem-num;
    	return t1*c[x][0][0]+t2*c[x][1][0]+rem*c[x][0][1]+num*c[x][1][1];
    }
    int main(){
    	n=read(),m=read(),memset(c,0x3f,sizeof(c));
    	for(int i=1;i<=m;i++) A[i]=read();
    	for(int T=read();T;T--){
    		int x=read(),y=read(),tg=0,k,typ;
    		typ=gc(),k=read(); if(x>y) swap(x,y),tg=1;
    		if(!P.count(mp(x,y))) P[mp(x,y)]=++cnt;
    		dw(c[P[mp(x,y)]][tg][typ],(LL)k);
    	}
    	for(int i=m;i>=2;i--) link(P[mp(min(A[i-1],A[i]),max(A[i-1],A[i]))],A[i-1]>A[i]);
    	for(int j=1;j<=cnt;j++){
    		if(!fs[j]) continue; top=0;
    		for(int i=fs[j];i;i=nt[i]){
    			K[++top]=kd[i],s[top][0]=s[top-1][0];
    			s[top][1]=s[top-1][1],s[top][kd[i]]++;
    		} ans+=solve(j);
    	} printf("%lld
    ",ans); return 0;
    }
  • 相关阅读:
    中级实训Android学习记录——百度地图API显示定位
    中级实训Android学习记录——Android Studio工程配置并进行地图显示
    中级实训Android学习记录——百度地图API获取AK
    unity 3d 八、粒子系统与流动效果
    中级实训Android学习记录——项目3制作
    中级实训Android学习记录——RecyclerView、Android存储
    中级实训Android学习记录——项目1、2重铸记录
    裴蜀定理
    二分模板
    最短路问题
  • 原文地址:https://www.cnblogs.com/OYJason/p/9877047.html
Copyright © 2011-2022 走看看