「题解」「CF853B」Jury Meeting
题目
思路
十分巧妙的差分前缀和好题。
题目板块完结之后,我看到有很多处理此题的方法,但总感觉差分前缀和比较巧妙。
首先,通过输入我们可以将每个人能在 \(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\) 的大小关系:
- \(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\) (仔细想想,为什么?);
- \(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的更多相关文章
- 「ZJOI2019」&「十二省联考 2019」题解索引
「ZJOI2019」&「十二省联考 2019」题解索引 「ZJOI2019」 「ZJOI2019」线段树 「ZJOI2019」Minimax 搜索 「十二省联考 2019」 「十二省联考 20 ...
- 「题解」「美团 CodeM 资格赛」跳格子
目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞 ...
- 「题解」「HNOI2013」切糕
文章目录 「题解」「HNOI2013」切糕 题目描述 思路分析及代码 题目分析 题解及代码 「题解」「HNOI2013」切糕 题目描述 点这里 思路分析及代码 题目分析 这道题的题目可以说得上是史上最 ...
- 「题解」JOIOI 王国
「题解」JOIOI 王国 题目描述 考场思考 正解 题目描述 点这里 考场思考 因为时间不太够了,直接一上来就着手暴力.但是本人太菜,居然暴力爆 000 ,然后当场自闭- 一气之下,发现对 60pts ...
- 【题解】「P6832」[Cnoi2020]子弦
[题解]「P6832」[Cnoi2020]子弦第一次写月赛题解( 首先第一眼看到这题,怎么感觉要用 \(\texttt{SAM}\) 什么高科技的?结果一仔细读题,简单模拟即可. 我们不难想出,出现最 ...
- 「题解报告」 P3167 [CQOI2014]通配符匹配
「题解报告」 P3167 [CQOI2014]通配符匹配 思路 *和?显然无法直接匹配,但是可以发现「通配符个数不超过 \(10\) 」,那么我们可以考虑分段匹配. 我们首先把原字符串分成多个以一个通 ...
- 「bzoj1003」「ZJOI2006」物流运输 最短路+区间dp
「bzoj1003」「ZJOI2006」物流运输---------------------------------------------------------------------------- ...
- 「bzoj1925」「Sdoi2010」地精部落 (计数型dp)
「bzoj1925」「Sdoi2010」地精部落---------------------------------------------------------------------------- ...
- 「BZOJ1924」「SDOI2010」 所驼门王的宝藏 tarjan + dp(DAG 最长路)
「BZOJ1924」[SDOI2010] 所驼门王的宝藏 tarjan + dp(DAG 最长路) -------------------------------------------------- ...
- 「LOJ#10051」「一本通 2.3 例 3」Nikitosh 和异或(Trie
题目描述 原题来自:CODECHEF September Challenge 2015 REBXOR 1≤r1<l2≤r2≤N,x⨁yx\bigoplus yx⨁y 表示 ...
随机推荐
- Winform中怎样对窗体进行隐藏,再次打开时仍然保留上次的窗体
场景 点击按钮后打开窗口,点击窗口的确定按钮后即使窗体返回了Ok,此时不关闭窗体,将窗体隐藏. 再次点击按钮后,仍然打开上次的窗体. 注: 博客主页: https://blog.csdn.net/ba ...
- JS表单验证源码(带错误提示及密码等级)
先晒图 index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...
- Codeforces Round #592 (Div. 2) E
给你一个数组,你最多可以进行k次操作,每次操作可以使一个数+1或者-1,问操作之后数组的极差最小可能是多少 利用map来模拟移动,可以观察到每次应该选择数量少的一组数让他们进行移动是最优的 int m ...
- conda使用以前安装的python环境
在装anaconda时,很多时候,我们自己之前安装了python环境,里面装了很多的包,不想换,所以想直接使用原来的python环境,所以可以使用以下命令: conda create --prefix ...
- sqlmap注入基本教程
附上一个别人总结的:https://www.cnblogs.com/ichunqiu/p/5805108.html 一套基础的sqlmap语句: python sqlmap.py -u "h ...
- [CF1303B] National Project - 数学
Solution \(2a>n\),一次性结束,直接输出 \(n\) \(a \geq b\),那么一直修即可,直接输出 \(n\) 否则,\(a\) 占弱势,我们考虑用 \(a\) 修一半需要 ...
- 03_TypeScript函数
1.函数的定义 es5定义函数的方法 //函数声明法 function run(){ return 'run'; } //函数表达式 var run = function(){ return 'run ...
- python基础(1):第一个python程序的编写
1.第一个python编程 1.1 python的安装 1> https://www.python.org/ 进入python官网,选择目标版本进行download 2> 点击setup ...
- C 库函数 - fmod()
C 库函数 - fmod() 转自: C 标准库 - <math.h> 描述 C 库函数 double fmod(double x, double y) 返回 x 除以 y 的余数. 声明 ...
- RYU安装教程
一.使用pip的形式安装RYU 1.首先检查ubuntu中是否存在pip,命令为 sudo pip3 --version 2.如果存在则使用默认版本8.1.1就行不必跟新,否则自己下载一个pip 3. ...