欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

洗衣服wash 题解

程序员文章站 2022-03-26 11:31:29
...

洗衣服

【题目描述】

nn 个人来到BBBB家里洗衣服,第ii个人的到达时间是 tit_i

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

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

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

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

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

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

【输入数据】

第一行三个整数 nn,xx,mm

第二行 nn 个整数 t1tnt_1 {-} t_n

【输出数据】

y=iy=i 时答案为 ansians_i,输出一行一个整数(ans1)(2×ans2)(3×ans3)(m×ansm)(ans_1)\oplus(2\times ans_2)\oplus(3\times ans_3)\oplus\cdots\oplus(m\times ans_m)

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

【样例输入】

4 2 10
1 2 2 3

【样例输出】

113

【样例解释】

压缩前的答案为

4 5 5 6 7 8 8 9 9 9

【数据范围】

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

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

对于 50%50\%的数据,n105n\leq 10^5

对于另外 20%20\% 的数据,n106n\leq 10^6mx20m-x\leq 20

对于 100%100\%的数据,1n,x,m1071\leq n,x,m\leq 10^71ti1091\leq t_i\leq 10^9titi+1t_i\leq t_{i+1}


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

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

nn个人使用了洗衣机会让答案至少为tn+xt_n+x,第n1n-1个人使用洗衣机会让答案至少为tn1+2xt_{n-1}+2x\cdots,第ii个人使用了洗衣机会使答案至少为ti+(ni+1)xt_i+(n-i+1)x。那么最终的答案就是max(t[i]+min(y,(ni+1)x))max(t[i]+min(y,(n-i+1)x))

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

考虑如何优化:

利用数学知识:

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

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

洗衣服wash 题解
将每一个不同的有关 yy的分段函数绘出然后综合,对于每一个yy,最终函数图像上的最高点即为对应yy的答案。

对应的代码为:

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]);
}

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

画个图解释就是:

洗衣服wash 题解

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

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

然后就成功将O(nm)O(nm)的算法优化成了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;
}