洗衣服wash 题解
洗衣服
【题目描述】
有 个人来到家里洗衣服,第个人的到达时间是 。
不幸的是, 家里只有一个洗衣机。
因此,同一时刻如果有多个人一起洗衣服的话,只能有一个人使用洗衣机,其他人只能手洗。
洗衣机洗一个人的衣服需要 的时间。
所有人手洗的速度是一样的,洗自己的衣服需要 的时间。
一个人的衣服不能在洗到一半的时候更换洗的方式。
给定 和 ,对于 ,分别求出所有人都洗完衣服的最早时刻。
【输入数据】
第一行三个整数 ,,。
第二行 个整数 。
【输出数据】
记 时答案为 ,输出一行一个整数
其中为计算机中的异或操作
【样例输入】
4 2 10
1 2 2 3
【样例输出】
113
【样例解释】
压缩前的答案为
4 5 5 6 7 8 8 9 9 9
【数据范围】
对于 的数据,。
对于 的数据,。
对于 的数据,。
对于另外 的数据,,。
对于 的数据,,,
对于此题,首先可以考虑一个人使用了洗衣机之后对后面的人造成的影响,但是会发现这样不太好维护,因为存在第个人使用手洗时间比第个人机洗要慢的情况。
但是,如果知道了之后有多少个人会使用洗衣机,这样的话就能倒序计算出答案了。
第个人使用了洗衣机会让答案至少为,第个人使用洗衣机会让答案至少为,,第个人使用了洗衣机会使答案至少为。那么最终的答案就是
但是直接枚举会使得复杂度为
考虑如何优化:
利用数学知识:
先将答案用分段函数的形式表达出来:
将函数绘出可以得到此图:
将每一个不同的有关 的分段函数绘出然后综合,对于每一个,最终函数图像上的最高点即为对应的答案。
对应的代码为:
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;
}
然后就成功将的算法优化成了的
完整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;
}
上一篇: UPC1491 【贪心】未出现的子串
下一篇: 深搜