做题记录 2021.9.10

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(nk+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];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值