题目

传送门

思路

十分巧妙的差分前缀和好题。

题目板块完结之后,我看到有很多处理此题的方法,但总感觉差分前缀和比较巧妙。

首先,通过输入我们可以将每个人能在 \(0\) 号点停留的最大时间区间 \([tl,tr]\) ,并将所有人的 \([tl,tr]\) 取交集,得到 \([ll,rr]\) 即表示只有在这个区间中所有人能够聚集在一起。

显然,如果 \(rr-ll-1<k\) 则直接 puts("-1") 即可。

然后怎么办?假设所有人聚集的时间从 \(i\) 开始到 \(i+k+1\) 或者更久,那么我们可以保证他们工作的时常至少为 \(k\) ,那么我们需要找的就是所有人在 \([1,i]\) 时间段内到 \(0\) 的最小花费以及 \([i+k+1,n]\) 时间段返回的最小花费之和。

两种情况是一样的,我们只讨论其中一种,不妨讨论前往 \(0\) 的情况。

对于一个人,我们假设他在 \(i\) 时刻到达 \(0\) 最便宜的价格为 \(m_i\),再将他的所有前往 \(0\) 的航班按时间顺序由小到大排序。

规定:\(t_i\) 表示第 \(i\) 趟航班起飞的时间,\(c_i\) 为其花费,\(m_i\) 为这个人在 \(i\) 时刻到达 \(0\) 的最小花费。

现在我们分析他的第一堂航班和第二趟航班,由于 \(t\) 我们已经按序排序了,现在讨论 \(c\) 的大小关系:

  1. \(c_1\le c_2\) ,那么这个人坐第一趟航班肯定是最便宜的,而且我们可以对 \(m_i\) 数组进行修改,即 \(\forall m_i,t_1\le i<t_3,m_i=c_1\) ,注意,此处 \(i<t_3\) 而非 \(t_2\) (仔细想想,为什么?);
  2. \(c_1>c_2\) ,此刻我们发现,在时间 \(i\) 介于区间 \([t_1,t_2)\) 的时候,肯定只能乘坐第一趟航班,但如果 \(i\ge t_2\) ,我们乘坐第二趟航班无疑最优,即当 \(t_1\le i < t_2\) 时,\(m_i=c_1\) ,当 \(i\le t_2\) 时,\(m_i=c_2\) ;

将我们的分析推广到整个体系当中:

在枚举当前是第 \(i\) 趟航班时,保留 \(1,2,\ldots i-1\) 趟航班中的最小花费 \(\min\) 。

  • 如果 \(c_i<\min\) ,那么我们更新 \(\min\) ,并用 \(c_i\) 将 \(m_i,i\in [t_i,t_{i+1})\) 全部更新;
  • 如果 \(c_i\ge \min\) ,那么我们保留 \(\min\) ,并用 \(\min\) 将 \(m_i,i\in [t_i,t_{i+1}]\) 全部更新;

至于从 \(0\) 返回希望大家自行分析,因为代码中有一些 \(+1\) 如果没有分析是很难弄懂的。

经过分析,我们发现这个操作十分像区间赋值,那么这里就有许多数据结构和思想值得我们使用:

  • 线段树
  • 树状数组
  • 差分前缀和

个人推荐差分前缀和,因为前两者的修改、询问都是 \(\mathcal O(\log N)\) 的,后者修改 \(\mathcal O(1)\) ,询问 \(\mathcal O(\log N)\),而基于我们的分析似乎修改操作十分繁杂,而询问操作只有在最后计算答案时使用。

那么我们对于每一个人,可以开一个 \(ansl[i][t]\) 表示这个人 \(i\) 在 \(t\) 时刻到 \(0\) ,再开一个 \(ansr[i][t]\) 表示这个人再 \(t\) 时刻离开 \(0\) 。但是人有 \(10^5\) 个,时间刻度有 \(10^6\) 个,开二维肯定不限时,但由于人与人之间相互独立,没有什么影响,我们考虑所有人共用一个 \(ansl\) 和一个 \(ansr\) 数组。

具体细节见代码。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<vector>
#include<utility>
using namespace std; #define rep(i,__l,__r) for(signed i=__l,i##_end_=__r;i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=__l,i##_end_=__r;i>=i##_end_;--i)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
#define LL long long
#define ull unsigned long long
#define uint unsigned int
#define pii pair< int,int >
#define Endl putchar('\n')
#define CODEFAIL puts("-1"),exit(0)
// #define FILEOI
// #define int long long
// #define int unsigned #ifdef FILEOI
# define MAXBUFFERSIZE 500000
inline char fgetc(){
static char buf[MAXBUFFERSIZE+5],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXBUFFERSIZE,stdin),p1==p2)?EOF:*p1++;
}
# undef MAXBUFFERSIZE
# define cg (c=fgetc())
#else
# define cg (c=getchar())
#endif
template<class T>inline void qread(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
inline int qread(){
int x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
// template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
template<class T>void fwrit(const T x){
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);
putchar(x%10^48);
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
} const int MAXN=1e5;
const int MAXM=1e5;
const int MAXK=1e6;
const int INF=(1<<30)-1; int n,m,k,ll,rr;
vector< pii >a[MAXN+5],b[MAXN+5];
//a[i] : 第 i 个点到 0 点的时间, 花费
//b[i] : 0 点到 i 点的时间, 花费 inline void input(){
n=qread(),m=qread(),k=qread();
for(int i=1,d,f,t,c;i<=m;++i){//照常规输入即可
d=qread(),f=qread(),t=qread(),c=qread();
if(f==0)b[t].push_back(mp(d,c));
else a[f].push_back(mp(d,c));
}
} inline void init(){
ll=-1,rr=INF;
int tl,tr;
rep(i,1,n){
sort(a[i].begin(),a[i].end());
sort(b[i].begin(),b[i].end());
tl=INF,tr=-1;
if(!a[i].empty())tl=a[i].begin()->first;
if(!b[i].empty())tr=b[i].back().first;
if(tl==INF || tr==-1)CODEFAIL;//如果连来的机票或者回去的机票的没有, 直接 gg
ll=Max(ll,tl),rr=Min(rr,tr);//取交集
// printf("i == %d, tl == %d, tr == %d\n",i,tl,tr);
}
// printf("ll == %d, rr == %d\n",ll,rr);
if(ll==-1 || rr==INF || rr-ll-1<k)CODEFAIL;//如果缺机票或者全部人最大的交集都不够 k 天也 gg 了
} LL ansl[MAXK+5],ansr[MAXK+5],res=(1ll<<60)-1;
inline void solve(){
for(int i=1,now,cost;i<=n;++i){
now=1,cost=INF;//初始化
// puts("For into ansl");
for(int t=0,siz=a[i].size(),tmp;t<siz;++t){
// printf("When i == %d, now == %d, cost == %d\n",i,now,cost);
tmp=a[i][t].first;
ansl[tmp]-=cost;
ansl[now]+=cost;
//差分前缀和的基本操作
//注意:此处有别于下面, 原因在于这里是处理前往 0 点而非离开 0 点
now=tmp,cost=Min(cost,a[i][t].second);
// printf("After i == %d, now == %d, cost == %d\n",i,now,cost);
}
ansl[MAXK+1]-=cost;
ansl[now]+=cost;
now=MAXK,cost=INF;//倒着处理
for(int t=b[i].size()-1,tmp;t>=0;--t){
tmp=b[i][t].first;
ansr[now+1]-=cost,ansr[tmp+1]+=cost;
now=tmp,cost=Min(cost,b[i][t].second);
}
ansr[1]+=cost,ansr[now+1]-=cost;
// printf("After i == %d, the two arr:\n",i);
// rep(t,1,20)writc(ansl[t],' ');Endl;
// rep(t,1,20)writc(ansr[t],' ');Endl;
}
rep(i,1,MAXK)ansl[i]+=ansl[i-1],ansr[i]+=ansr[i-1];//差分前缀和数组的最后一步
// rep(i,1,20)writc(ansl[i],' ');
// Endl;
// rep(i,1,20)writc(ansr[i],' ');
// Endl;
for(int i=ll;i+k+1<=rr;++i)res=Min(res,ansl[i]+ansr[i+k+1]);
writc(res,'\n');
} signed main(){
#ifdef FILEOI
freopen("file.in","r",stdin);
freopen("file.out","w",stdout);
#endif
input();
init();
solve();
return 0;
}

似乎有点贪心?

「题解」「CF853B」Jury Meeting的更多相关文章

  1. 「ZJOI2019」&「十二省联考 2019」题解索引

    「ZJOI2019」&「十二省联考 2019」题解索引 「ZJOI2019」 「ZJOI2019」线段树 「ZJOI2019」Minimax 搜索 「十二省联考 2019」 「十二省联考 20 ...

  2. 「题解」「美团 CodeM 资格赛」跳格子

    目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞 ...

  3. 「题解」「HNOI2013」切糕

    文章目录 「题解」「HNOI2013」切糕 题目描述 思路分析及代码 题目分析 题解及代码 「题解」「HNOI2013」切糕 题目描述 点这里 思路分析及代码 题目分析 这道题的题目可以说得上是史上最 ...

  4. 「题解」JOIOI 王国

    「题解」JOIOI 王国 题目描述 考场思考 正解 题目描述 点这里 考场思考 因为时间不太够了,直接一上来就着手暴力.但是本人太菜,居然暴力爆 000 ,然后当场自闭- 一气之下,发现对 60pts ...

  5. 【题解】「P6832」[Cnoi2020]子弦

    [题解]「P6832」[Cnoi2020]子弦第一次写月赛题解( 首先第一眼看到这题,怎么感觉要用 \(\texttt{SAM}\) 什么高科技的?结果一仔细读题,简单模拟即可. 我们不难想出,出现最 ...

  6. 「题解报告」 P3167 [CQOI2014]通配符匹配

    「题解报告」 P3167 [CQOI2014]通配符匹配 思路 *和?显然无法直接匹配,但是可以发现「通配符个数不超过 \(10\) 」,那么我们可以考虑分段匹配. 我们首先把原字符串分成多个以一个通 ...

  7. 「bzoj1003」「ZJOI2006」物流运输 最短路+区间dp

    「bzoj1003」「ZJOI2006」物流运输---------------------------------------------------------------------------- ...

  8. 「bzoj1925」「Sdoi2010」地精部落 (计数型dp)

    「bzoj1925」「Sdoi2010」地精部落---------------------------------------------------------------------------- ...

  9. 「BZOJ1924」「SDOI2010」 所驼门王的宝藏 tarjan + dp(DAG 最长路)

    「BZOJ1924」[SDOI2010] 所驼门王的宝藏 tarjan + dp(DAG 最长路) -------------------------------------------------- ...

  10. 「LOJ#10051」「一本通 2.3 例 3」Nikitosh 和异或(Trie

    题目描述 原题来自:CODECHEF September Challenge 2015 REBXOR 1​​≤r​1​​<l​2​​≤r​2​​≤N,x⨁yx\bigoplus yx⨁y 表示 ...

随机推荐

  1. Java数列循环左移

    描述 有n个整数组成一个数组(数列).现使数列中各数顺序依次向左移动k个位置,移出的数再从尾部移入.输出移动后的数列元素. 题目没有告诉你n的范围,要求不要提前定义数组的大小. 另外要求定义并使用函数 ...

  2. javascript当中arguments用法

    8)arguments 例 3.8.1<head>    <meta http-equiv="content-type" content="text/h ...

  3. 安卓平台SQLite数据库基础操作总结

    最近学了一些安卓开发,在这里分享一下SQLite数据库的使用相关部分,我使用的工具为Android Studio,后台语言为java: 首先,需要创建一个数据库辅助类DataBaseHelper,用于 ...

  4. Bell数

    事实上,\[e^{(e^t-1)x}=\sum_{k=0}^{\infty}\frac{B_k(x)}{k!}.\]\[B_n(x)=x\sum_{k=1}^{n}\binom{n-1}{k-1}B_ ...

  5. Wannafly Camp 2020 Day 3F 社团管理 - 决策单调性dp,整体二分

    有 \(n\) 个数构成的序列 \({a_i}\),要将它划分为 \(k\) 段,定义每一段的权值为这段中 \((i,j) \ s.t. \ i<j,\ a_i=a_j\) 的个数,求一种划分方 ...

  6. Pikachu-over permission(越权操作)

    如果使用A用户的权限去操作B用户的数据,A的权限小于B的权限,如果能够成功操作,则称之为越权操作. 越权漏洞形成的原因是后台使用了 不合理的权限校验规则导致的. 一般越权漏洞容易出现在权限页面(需要登 ...

  7. HDU 4544 湫湫系列故事——消灭兔子 (优先队列)

    湫湫减肥  越减越肥!    最近,减肥失败的湫湫为发泄心中郁闷,在玩一个消灭免子的游戏.  游戏规则很简单,用箭杀死免子即可.  箭是一种消耗品,已知有M种不同类型的箭可以选择,并且每种箭都会对兔子 ...

  8. KafkaUtils.createDirectStream报错Cannot resolve symbol createDirectStream

    一开以为是自己导包导错了,但是对比了一下之前的程序发现并没有错, import org.apache.spark.streaming.kafka.{HasOffsetRanges, KafkaUtil ...

  9. BZOJ3531 SDOI2014 旅行 - 树链剖分,主席树

    题意:给定一棵树,树上每个点有权值和类型.支持:修改某个点的类型:修改某个点的权值:询问某条链上某个类型的点的和/最大值.点数/类型数/询问数<=100000. 分析: 树链剖分,对每个类型的点 ...

  10. start.sh在linux下启动报错 Can't connect to any repository: ,cannot open git-receive-pack

    个人博客 地址:http://www.wenhaofan.com/article/20181223135418 报错信息 Can't connect to any repository: ,canno ...