题目

传送门

思路

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

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

首先,通过输入我们可以将每个人能在 \(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. Winform中怎样对窗体进行隐藏,再次打开时仍然保留上次的窗体

    场景 点击按钮后打开窗口,点击窗口的确定按钮后即使窗体返回了Ok,此时不关闭窗体,将窗体隐藏. 再次点击按钮后,仍然打开上次的窗体. 注: 博客主页: https://blog.csdn.net/ba ...

  2. JS表单验证源码(带错误提示及密码等级)

    先晒图 index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...

  3. Codeforces Round #592 (Div. 2) E

    给你一个数组,你最多可以进行k次操作,每次操作可以使一个数+1或者-1,问操作之后数组的极差最小可能是多少 利用map来模拟移动,可以观察到每次应该选择数量少的一组数让他们进行移动是最优的 int m ...

  4. conda使用以前安装的python环境

    在装anaconda时,很多时候,我们自己之前安装了python环境,里面装了很多的包,不想换,所以想直接使用原来的python环境,所以可以使用以下命令: conda create --prefix ...

  5. sqlmap注入基本教程

    附上一个别人总结的:https://www.cnblogs.com/ichunqiu/p/5805108.html 一套基础的sqlmap语句: python sqlmap.py -u "h ...

  6. [CF1303B] National Project - 数学

    Solution \(2a>n\),一次性结束,直接输出 \(n\) \(a \geq b\),那么一直修即可,直接输出 \(n\) 否则,\(a\) 占弱势,我们考虑用 \(a\) 修一半需要 ...

  7. 03_TypeScript函数

    1.函数的定义 es5定义函数的方法 //函数声明法 function run(){ return 'run'; } //函数表达式 var run = function(){ return 'run ...

  8. python基础(1):第一个python程序的编写

    1.第一个python编程 1.1 python的安装 1> https://www.python.org/  进入python官网,选择目标版本进行download 2> 点击setup ...

  9. C 库函数 - fmod()

    C 库函数 - fmod() 转自: C 标准库 - <math.h> 描述 C 库函数 double fmod(double x, double y) 返回 x 除以 y 的余数. 声明 ...

  10. RYU安装教程

    一.使用pip的形式安装RYU 1.首先检查ubuntu中是否存在pip,命令为 sudo pip3 --version 2.如果存在则使用默认版本8.1.1就行不必跟新,否则自己下载一个pip 3. ...