题解-P6040 「ACOI2020」课后期末考试滑溜滑溜补习班
- 题目意思
题目较长,不便于描述
这道题目就是考察了一道基础的单调队列优化,以及化柿子的方法。
,暴力
设表示到
的最小花费精力,转移
即可
if(n<=1000)
{
memset(f,127/3,sizeof(f));
f[1]=a[1];
for ( int i=2;i<=n;i++ )
for ( int j=max(1ll,i-X);j<i;j++ )
f[i]=min(f[i],f[j]+K+(i-j-1)*D+a[i]);
printf("%lld\n",f[n]);
exit(0);
} ,单调队列优化
对于上述柿子我们可以进行移项合并得到:
到这里我们很容易想到用单调队列去维护单减即可,于是就是单调队列的基本操作了。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+5;
int n,m,K,D,X,type,a[N],f[N],q[N],Seed;
inline int read()
{
int sum=0; char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum;
}
inline int rnd ()
{
static const int MOD = 1e9;
return Seed=(1ll*Seed*0x66CCFF%MOD+20120712)%MOD;
}
inline void Sub()
{
for ( int i=1;i<=n;i++ ) a[i]=read();
if(n<=1000)
{
memset(f,127/3,sizeof(f));
f[1]=a[1];
for ( int i=2;i<=n;i++ )
for ( int j=max(1ll,i-X);j<i;j++ )
f[i]=min(f[i],f[j]+K+(i-j-1)*D+a[i]);
printf("%lld\n",f[n]);
exit(0);
}
f[1]=a[1];
int head=1,tail=1;
q[1]=1;
for ( int i=2;i<=n;i++ )
{
while(head<=tail&&i-q[head]>X) head++;
f[i]=f[q[head]]+K+(i-q[head]-1)*D+a[i];
while(head<=tail&&f[q[tail]]-q[tail]*D>=f[i]-i*D) tail--;
q[++tail]=i;
}
printf("%lld\n",f[n]);
exit(0);
}
inline void Sub1()
{
Seed=read();
for ( int i=1;i<=n;i++ ) a[i]=rnd();
f[1]=a[1];
int head=1,tail=1;
q[1]=1;
for ( int i=2;i<=n;i++ )
{
while(head<=tail&&i-q[head]>X) head++;
f[i]=f[q[head]]+K+(i-q[head]-1)*D+a[i];
while(head<=tail&&f[q[tail]]-q[tail]*D>=f[i]-i*D) tail--;
q[++tail]=i;
}
printf("%lld\n",f[n]);
exit(0);
}
signed main()
{
n=read();
K=read();
D=read();
X=read();
type=read();
if(!type) Sub();
else Sub1();
return 0;
}
/*
10 30630 56910 2 0
7484 99194 86969 17540 29184 68691 91892 81564 93999 74280
717318
*/

京公网安备 11010502036488号