zoukankan      html  css  js  c++  java
  • P2882 [USACO07MAR]Face The Right Way [贪心+模拟]

    题目描述

    N头牛排成一列1<=N<=5000。每头牛或者向前或者向后。为了让所有牛都 面向前方,农夫每次可以将K头连续的牛转向1<=K<=N,求操作的最少 次数M和对应的最小K。

    简单题意:给你一个01串,每次可以对长度为K的区间进行异或,求异或的最少次数以及对应的K。

    解析:

    这是一道有毒的模拟,我做了一个下午加加减减鼓捣半天都快吐(秃)了。

    看到题第一反应二分答案,不过仔细一想,K和M并不相关,答案不具备单调性,无法二分出解。

    所以,这道题其实是个模拟。

    一个显而易见的贪心:从左往右,遇到0就以它为起点的K个点做异或,显然是最优的,每个0都至少要被异或一次,如果线性异或的话可以保证每个0只被异或一次,否则一定不优。

    于是枚举K找答案。直接暴力模拟复杂度达到(O(n^3)),80pnts,无法接受。

    考虑一个类似差分的优化,对于某一为0的位置(i),假设当前使用的长度为(X),那么我们在这个0的位置(i)打个标记(A),再在位置(i+X)的位置打个标记(B),表示从(A)开始到(B)进行了一次异或。

    思考如何去打这个标记(卡我一下午),直接差分肯定是不行的。我们可以讨论任意一个位置(i),看它前面有多少个(A,B)标记,发现位置(i)的异或次数正是该位置前面(A)的标记数量-(B)的标记数量((A)的量一定大于(B),这点很好理解)。

    于是代码实现我又卡了(我好蒻)。

    换个思路。

    思考直接用异或打标记,方便又好理解,搞一个数组去记录标记(B)(A)标记我们可以直接在枚举时实现。

    考虑用一个类似指针的东西当作标记(A)(有点不同于前面的(A)),在数组种从左往右移动,初值为0,遇到不同的数就对1进行异或,表示从这个遇到的不同的数位置开始进行翻转(有点绕),直到遇到一个标记(B)再把它异或回去为止。值得注意的是,这里我们并不需要对原数组进行改变,实际上(A)标记已经帮我们实现了“对(A)(B)这个区间进行异或”的目的了(想一想,为什么)。这个确实有点难以理解,毕竟我搞了一下午呢

    如果用之前那种打标记法我觉得比较难理解,毕竟异或比较贴近原题,虽然而者本质相同。

    参考代码:

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<ctime>
    #include<cstdlib>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #define INF 0x3f3f3f3f
    #define N 5010
    using namespace std;
    int n,a[N],sum[N],d[N];
    int main()
    {
    	scanf("%d",&n);
    	char c;
    	for(int i=1;i<=n;++i){getchar();c=getchar();(c=='B')?a[i]=0:a[i]=1;}
    	int cnt=0,ans=INF,pos;
    	for(int k=1;k<=n;++k){
    		int flag=0;cnt=0;
    		bool can=1;
    		memset(d,0,sizeof(d));
    		for(int i=1;i<=n;i++){
    			flag^=d[i];
    			if(!a[i]^flag){
    				if(i+k-1>n){can=0;break;}
    				flag^=1,d[i+k]^=1;cnt++;
    			}
    		}
    		if(can&&ans>cnt) ans=cnt,pos=k; 
    	}
    	cout<<pos<<' '<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    [日常摸鱼]最小费用最大流
    [日常摸鱼]loj6000「网络流 24 题」搭配飞行员
    [日常摸鱼]最大流
    [日常摸鱼]poj1741Tree-点分治
    [游记]FCS&FJOI2018滚粗记
    TOJ-1469-Wooden Sticks(贪心)
    TOJ-1188-田忌赛马(贪心)
    TOJ3988-Password(已知二叉树前中序求后序)
    枚举HDU-1172猜数字
    模拟题 HDU3052 VIM
  • 原文地址:https://www.cnblogs.com/DarkValkyrie/p/11256863.html
Copyright © 2011-2022 走看看