这题好难啊!!!有一篇博客已经写得很详细也很清晰了,安利一下:传送门
我再加几句,是我自己理解过程中遇到的困难:
(1)逆行的车用(N−S(a,i−1)−S(q,i),N−S(a,i)−S(q,i))表示,为什么N可以调整为K的倍数。
解释:因为所有火车同时推迟t个单位时间本质上和原来一样,所以我们可以通过推迟的方法让N变为K的倍数。
(2)为什么最后答案不是S(p,n)+S(q,n)+2*S(a,n),而是S(p,n)-p[1]+S(q,n)-q[1]+2*S(a,n)。
解释:火车在最左边一个站的等待时间其实是不算到答案里的,这里只是为了方便我们找到出发时间和N的相对关系,才添加了一个p[1]和q[1],这并不算到代价里。
#include
#include
#define lf (x<<1)
#define rg (lf^1)
#define ll long long
#define rep(i,j,k) for (i=j;i<=k;i++)
#define down(i,j,k) for (i=j;i>=k;i--)
using namespace std;
const int N=1e5+5;
int n,k,i,a[N],b[N];
ll ans,sum[N],dp[N];
int cn,id,tmp[N*2],seg[N*4],L[N],R[N];
ll mo(ll x) {
return (x%k+k)%k;
}
void pushdown(int x) {
if (!seg[x]) return ;
seg[lf]=seg[x]; seg[rg]=seg[x]; seg[x]=0;
}
void updata(int x,int l,int r,int L,int R,int val)
{
if (rR) return;
if (L<=l && r<=R) {
seg[x]=val; return ;
}
int mid=(l+r)>>1;
pushdown(x);
updata(lf,l,mid,L,R,val);
updata(rg,mid+1,r,L,R,val);
}
void query(int x,int l,int r,int pos)
{
if (seg[x]) {
id=seg[x]; return ;
}
if (l==r) return ;
int mid=(l+r)>>1;
if (pos<=mid) query(lf,l,mid,pos);
else query(rg,mid+1,r,pos);
}
ll ask(int x)
{
id=0; query(1,1,cn,x);
if (!id) return 0;
return dp[id]+((ll)tmp[L[id]]-tmp[x]+k)%k;
}
int main()
{
scanf("%d%d",&n,&k);
rep(i,1,n) scanf("%d%d",&a[i],&b[i]);
rep(i,1,n) {
sum[i]=sum[i-1]+a[i];
if (b[i]==1) {
if (a[i]*2>k) { printf("-1\n"); return 0; }
R[i]=mo(-2*sum[i]);
L[i]=mo(-2*sum[i-1]);
}
else L[i]=0,R[i]=k-1;
}
rep(i,1,n) tmp[++cn]=L[i],tmp[++cn]=R[i];
sort(tmp+1,tmp+1+cn);
cn=unique(tmp+1,tmp+1+cn)-tmp-1;
down(i,n,1)
{
L[i]=lower_bound(tmp+1,tmp+1+cn,L[i])-tmp;
R[i]=lower_bound(tmp+1,tmp+1+cn,R[i])-tmp;
// printf("%d %d\n",L[i],R[i]);
dp[i]=ask(L[i]);
if (L[i]<=R[i]) {
if (L[i]>1) updata(1,1,cn,1,L[i]-1,i);
if (R[i]1) updata(1,1,cn,R[i]+1,L[i]-1,i);
}
ans=dp[1];
// rep(i,1,n) printf("%I64d ",dp[i]); printf("\n");
rep(i,1,cn) ans=min(ans,ask(i));
ans+=2*sum[n];
printf("%lld\n",ans);
return 0;
}