POJ3276 Face The Right Way
这道题可以采取如下思路:不难发现每个特定的区间反转超过1次是无意义的,且反转顺序对结果无影响,所以对于一个反转次数k,可以贪心地假定从第一个开始,如果当前为反面就反转连续k个,否则不反转。如果遇到需要反转但只能反转一部分的情况(即i+k>n),那就说明方案不成立。
最坏情况下,每个k要反转n-k+1次,每次反转k头牛,一共就要
∑
k
=
1
n
k
(
n
−
k
+
1
)
\sum_{k=1}^{n}k(n-k+1)
∑k=1nk(n−k+1)次,时间复杂度达到
O
(
n
3
)
O(n^3)
O(n3),显然不行。
本来想用二分答案优化,但由于k更大时反转次数反而可能更小,遂放弃。
正确思路:设置一个数组f[],,f[i]表示以i开始的区间是否被反转。很明显,对于任何一个i,如果它前面k-1个反转了偶数次,那么它的方向就还是原方向,否则就是反方向。可以用前缀和表示前面反转的次数,复杂度就降低到
O
(
n
2
)
O(n^2)
O(n2)。
参考代码:
inline void turn(int k,string s) {
fill(f+1,f+n+1,0);
fill(sum+1,sum+n+1,0); //sum为前缀和
for(int i=0; i<n; i++) {
int tme=sum[i]-sum[max(i-k+1,0)]; //算前面一共转了几次
if((s[i]=='F'&&tme%2==1)||(s[i]=='B'&&tme%2==0)) { //需要反转
if(i+k>n) {
sum[n]=n+1;
return; //方案不成立
}
f[i+1]=1;
}
sum[i+1]=sum[i]+(int)f[i+1];
}
}