洗衣服wash 题解

洗衣服

【题目描述】

n n n 个人来到 B B BB BB家里洗衣服,第 i i i个人的到达时间是 t i t_i ti

不幸的是, B B BB BB 家里只有一个洗衣机。

因此,同一时刻如果有多个人一起洗衣服的话,只能有一个人使用洗衣机,其他人只能手洗。

洗衣机洗一个人的衣服需要 x x x 的时间。

所有人手洗的速度是一样的,洗自己的衣服需要 y y y 的时间。

一个人的衣服不能在洗到一半的时候更换洗的方式。

给定 x x x m m m,对于 y = 1 , 2 ⋯   , m y=1,2\cdots,m y=1,2,m,分别求出所有人都洗完衣服的最早时刻。

【输入数据】

第一行三个整数 n n n, x x x, m m m

第二行 n n n 个整数 t 1 − t n t_1 {-} t_n t1tn

【输出数据】

y = i y=i y=i 时答案为 a n s i ans_i ansi,输出一行一个整数 ( a n s 1 ) ⊕ ( 2 × a n s 2 ) ⊕ ( 3 × a n s 3 ) ⊕ ⋯ ⊕ ( m × a n s m ) (ans_1)\oplus(2\times ans_2)\oplus(3\times ans_3)\oplus\cdots\oplus(m\times ans_m) (ans1)(2×ans2)(3×ans3)(m×ansm)

其中 ⊕ \oplus 为计算机中的异或操作

【样例输入】

4 2 10
1 2 2 3

【样例输出】

113

【样例解释】

压缩前的答案为

4 5 5 6 7 8 8 9 9 9

【数据范围】

对于 5 % 5\% 5%的数据, n , m ≤ 10 n,m\leq 10 n,m10

对于 25 % 25\% 25%的数据, n , m ≤ 1000 n,m\leq 1000 n,m1000

对于 50 % 50\% 50%的数据, n ≤ 1 0 5 n\leq 10^5 n105

对于另外 20 % 20\% 20% 的数据, n ≤ 1 0 6 n\leq 10^6 n106 m − x ≤ 20 m-x\leq 20 mx20

对于 100 % 100\% 100%的数据, 1 ≤ n , x , m ≤ 1 0 7 1\leq n,x,m\leq 10^7 1n,x,m107 1 ≤ t i ≤ 1 0 9 1\leq t_i\leq 10^9 1ti109 t i ≤ t i + 1 t_i\leq t_{i+1} titi+1


对于此题,首先可以考虑一个人使用了洗衣机之后对后面的人造成的影响,但是会发现这样不太好维护,因为存在第 i − 1 i-1 i1个人使用手洗时间比第 i i i个人机洗要慢的情况。

但是,如果知道了之后有多少个人会使用洗衣机,这样的话就能倒序计算出答案了。

n n n个人使用了洗衣机会让答案至少为 t n + x t_n+x tn+x,第 n − 1 n-1 n1个人使用洗衣机会让答案至少为 t n − 1 + 2 x t_{n-1}+2x tn1+2x ⋯ \cdots ,第 i i i个人使用了洗衣机会使答案至少为 t i + ( n − i + 1 ) x t_i+(n-i+1)x ti+(ni+1)x。那么最终的答案就是 m a x ( t [ i ] + m i n ( y , ( n − i + 1 ) x ) ) max(t[i]+min(y,(n-i+1)x)) max(t[i]+min(y,(ni+1)x))

但是直接枚举会使得复杂度为 O ( n m ) O(nm) O(nm)

考虑如何优化:

利用数学知识:

先将答案用分段函数的形式表达出来:

a n s [ i ] = m i n { t [ i ] + ( n − i + 1 ) x t [ i ] + y ans[i]=min \left\{\begin{aligned} t[i]+(n-i+1)x \\t[i]+y \end{aligned}\right. ans[i]=min{t[i]+(ni+1)xt[i]+y
将函数绘出可以得到此图:

在这里插入图片描述
将每一个不同的有关 y y y的分段函数绘出然后综合,对于每一个 y y y,最终函数图像上的最高点即为对应 y y y的答案。

对应的代码为:

for(int i=1;i<=n;i++)
{
    t=read<int>();
    ll tmp=1LL*(n-i+1)*x;
    if(tmp>m) 
    {
        ans[m]=max(ans[m],t+m);
    }
    else
    {
        ans[tmp]=max(1LL*ans[tmp],t+tmp);
    }
}

求出最高点之后再想办法求出函数,可以采用标记左下方的点的方法

先倒序枚举:

for(int i=m;i>=1;i--)
{
    ans[i]=max(ans[i+1]-1,ans[i]);
}

但是存在一种两个点在同一条斜率为零的线的情况:

画个图解释就是:

在这里插入图片描述

所以需要在再在最后统计答案的时候进行修正:

int k=ans[1];
for(int i=1;i<=m;i++)
{
    k=max(k,ans[i]);
    ans^=1LL*k*i;
}

然后就成功将 O ( n m ) O(nm) O(nm)的算法优化成了 O ( n + 2 m ) O(n+2m) O(n+2m)

完整code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int twx=1e7+100;
const int inf=0x3f3f3f3f;
int n,x,m;
int t;
int ans[twx];
ll ANS;
char buf[1<<20],*p1,*p2;
#define getchar() ((p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
template<class T>
T read()
{
	T r=0;
	int w=0,c;
	for(;!isdigit(c=getchar());r=c);
	for(w=(c^48);isdigit(c=getchar());w=w*10+(c^48));
	return r^45?w:-w;
}
void init()
{
	n=read<int>();
    x=read<int>();
    m=read<int>();
    for(int i=1;i<=n;i++)
    {
        t=read<int>();
        ll tmp=1LL*(n-i+1)*x;
        if(tmp>m) 
        {
            ans[m]=max(ans[m],t+m);
        }
        else
        {
            ans[tmp]=max(1LL*ans[tmp],t+tmp);
        }
    }
    for(int i=m;i>=1;i--)
    {
        ans[i]=max(ans[i+1]-1,ans[i]);
    }
    int k=ans[1];
    for(int i=1;i<=m;i++)
    {
        k=max(k,ans[i]);
        ANS^=1LL*k*i;
    }
    printf("%lld\n",ANS);
}
int main()
{
	//freopen("wash.in","r",stdin);
	//freopen("wash.out","w",stdout);
    init();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值