zoukankan      html  css  js  c++  java
  • CF 1278C Berry Jam 题解

    Forewords

    说实话我是被图吸引进来的23333,图画的真的挺好看。

    题意

    你从一个梯子下到地下室,梯子左右两边各有 (n) 瓶果酱排成一排,果酱口味为草莓味或蓝莓味,你每次只能吃你左边或右边没吃过的那瓶,求最少要吃多少瓶才能使两种口味的果酱数量相等。

    题解

    以样例为例,有 (7) 罐草莓味的和 (5) 罐蓝莓味的。
    img1
    然后一直往右边吃,吃到这个时候,吃掉了 (3) 草蓝莓味的和 (2) 罐蓝莓味的,剩下 (r_ ext{left}=4) 罐草莓味的和 (b_ ext{left}=3) 罐蓝莓味的。
    img2
    这时候,为了达到目的,可以再吃 (r) 罐草莓味的和 (b) 罐蓝莓味的,可行方案如下表:

    (r) (b)
    (1) (0)
    (2) (1)
    (3) (2)
    (dots) (dots)

    可以发现,(r-b) 保持不变,且等于 (r_ ext{left}-b_ ext{left})

    这一结论很显然,因为 (r)(b) 只能减,不能增,因此达到目标的最好方法就是把数量多的口味吃到和另一个口味数量相等。然而这个方案并不一定能够达到,因此在这个的基础上再两种口味同时多吃 (v) 瓶。

    具体实现就是预处理单吃一侧不同数量时产生的差值,然后枚举吃另一侧 (1dots n) 瓶时要在另一侧吃的差值对应去找即可。

    注意处理一下边界。

    Code

    这里因为带了个 map 所以复杂度是 (O(nlog n)),但是 map 可以优化成数组,降到 (O(n))(比官方给的题解少一个 (log))。

    运用了一些小技巧来对调两边(其实可能不需要)。

    #include<cstdio>
    #include<map>
    const int MAXN=1e5+5;
    int a[MAXN],b[MAXN],t,bflag[MAXN],n,gtotr,gtotb,ans;
    std::map<int,int>map;
    int main()
    {
    	scanf("%d",&t);
    	t*=2;
    	int cur=0;
    	for(;t>=1;t--)
    	{
    		map.clear();gtotr=gtotb=0;
    		if((++cur)%2)
    		{
    			ans=2147483647;
    			scanf("%d",&n);
    			for(int i=1;i<=n;i++)
    				scanf("%d",&a[i]);
    			for(int i=1;i<=n;i++)
    				scanf("%d",&b[i]);
    		}
    		else
    		{
    			for(int i=1;i<=n;i++)
    				std::swap(a[i],b[n-i+1]);
    			/*
    			for(int i=1;i<=n;i++)
    				printf("%d ",a[i]);
    			for(int i=1;i<=n;i++)
    				printf("%d ",b[i]);
    			printf("
    ");
    			*/
    		}
    		for(int i=1;i<=n;i++)
    		{
    			if(a[i]==1) gtotr++; else gtotb++;
    		}
    		int totr=0,totb=0;
    		map[0]=-1;
    		for(int i=1;i<=n;i++)
    		{
    			if(b[i]==1) totr++; else totb++;
    			bflag[i]=totr-totb;
    			if(!map[bflag[i]]) map[bflag[i]]=i;
    //			printf("%d %d
    ",bflag[i],i);
    		}
    		gtotr+=totr;gtotb+=totb;
    		if(gtotr==gtotb) {if(!(cur%2))printf("0
    ");continue;}
    		totr=totb=0;
    		for(int i=n;i>=1;i--)
    		{
    			if(a[i]==1) totr++; else totb++;
    			int result=map[(gtotr-totr)-(gtotb-totb)];
    //			printf("Eat [%d %d], Left[%d %d], Result %d
    ",totr,totb,gtotr-totr,gtotb-totb,(gtotr-totr)-(gtotb-totb));
    			if(result) {if(result<0) result=0;ans=std::min(ans,n-i+1+result);}
    		}
    		if(!(cur%2)) printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    无特别声明的情况下,本文为原创文章,允许转载,采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
    在声明禁止转载的情况下,请勿转载;若本文章为转载的文章,版权归原作者所有。
    如果您觉得本文写得好,请点击下方的推荐按钮~若您有任何建议和指正,请在下方留言,对于您的指正将不胜感激。
  • 相关阅读:
    AC自动机模板
    hdu 6034 贪心模拟 好坑
    UVA 10870
    hdu 2604 递推 矩阵快速幂
    hdu 3117 Fibonacci Numbers 矩阵快速幂+公式
    hdu 1575 Tr A 矩阵快速幂
    POJ_1151 扫描线+离散化+线段树
    HDU_2227 求不减子序列的个数(树状数组+DP)
    深夜敲模板_5——KMP
    深夜敲模板_4——无向图的割顶和桥
  • 原文地址:https://www.cnblogs.com/ksyx/p/coderforces-1278C-solution.html
Copyright © 2011-2022 走看看