题目大意:
题目链接:http://10.156.31.134/contestnew.aspx?cid=77 (学校局域网)
一只小猫在
n
n
n个时刻中每一个时刻可以不叫,叫一声或者叫两声。如果在第
i
i
i个时刻叫一声会得到
a
i
a_i
ai的权值,叫两声得到
a
i
2
{a_i}^2
ai2的权值,但是下一个时刻就不可以叫。求最大权值和。
思路:
很裸的
d
p
dp
dp,设
f
[
i
]
[
0
/
1
/
2
]
f[i][0/1/2]
f[i][0/1/2]分别表示这只猫在第
i
i
i个时刻不叫、叫一声、叫两声的最大权值和。方程也是很明显的,根据题目意思就可以推出来。这里就直接给出方程
f
[
i
]
[
0
]
=
m
a
x
(
f
[
i
−
1
]
[
0
]
,
f
[
i
−
1
]
[
1
]
,
f
[
i
−
1
]
[
2
]
)
f[i][0]=max(f[i-1][0],f[i-1][1],f[i-1][2])
f[i][0]=max(f[i−1][0],f[i−1][1],f[i−1][2])
f
[
i
]
[
1
]
=
m
a
x
(
f
[
i
−
1
]
[
0
]
,
f
[
i
−
1
]
[
1
]
)
+
a
[
i
]
f[i][1]=max(f[i-1][0],f[i-1][1])+a[i]
f[i][1]=max(f[i−1][0],f[i−1][1])+a[i]
f
[
i
]
[
2
]
=
m
a
x
(
f
[
i
−
1
]
[
0
]
,
f
[
i
−
1
]
[
1
]
)
+
a
[
i
]
2
f[i][2]=max(f[i-1][0],f[i-1][1])+a[i]^2
f[i][2]=max(f[i−1][0],f[i−1][1])+a[i]2
最终答案取个最大值就可以了。
关于卡常
由于学校题库的速度极慢,正常的
O
(
n
)
O(n)
O(n)算法会被T飞。所以可以考虑采用小数+负数的快读
,就可以轻松过了。
这里简单提几句方法吧。对于负数快读就只要在普通的快读中增加一个判断前面是否有负号即可。而小数快读的整数部分方法没变,若读到了小数点,那么就开始读小数部分,每次读入的数字除以
1
0
x
(
x
=
1
,
2...
)
10^x(x=1,2...)
10x(x=1,2...),加到整数部分即可。
代码:
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=800010;
int n;
double a[N],f[N][3];
double read()
{
double d=0,ff=1;
char ch=getchar();
while (ch<'0'||ch>'9')
{
if (ch=='-') ff=-1; //判断是否是负数
ch=getchar();
}
while (ch>='0'&&ch<='9') //正常的整数读入
d=d*10+(double)(ch-48),ch=getchar();
if (ch!='.') return d*ff; //如果没有小数点就直接返回了
double cnt=10;
ch=getchar();
while (ch>='0'&&ch<='9') //读入小数
d=d+((double)(ch-48)/cnt),ch=getchar(),cnt*=10.0;
return d*ff;
}
int main()
{
scanf("%d",&n);
for (register int i=1;i<=n;i++)
a[i]=read();
f[1][0]=0;
f[1][1]=a[1];
f[1][2]=a[1]*a[1];
for (register int i=2;i<=n;i++)
{
f[i][0]=max(f[i-1][0],max(f[i-1][1],f[i-1][2]));
f[i][1]=max(f[i-1][0],f[i-1][1])+a[i];
f[i][2]=max(f[i-1][0],f[i-1][1])+a[i]*a[i];
}
printf("%0.4lf\n",max(f[n][0],max(f[n][1],f[n][2])));
return 0;
}