• Luogu P4552 [Poetize6] IncDec Sequence|差分


    题目链接
    题目大意:
    给定一个长度为 (n) 的数列 { (a_1) , (a_2),(cdots),(a_n)} ,每次可以选择一个区间([l,r]),使这个区间内的数都加 (1) 或者都减 (1)

    请问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。

    题目思路:

    以下的解法可能不是最优,敬请留意。

    这种序列题常常会用到前缀和/差分进行求解。由于本题要求最后数字相同,可以想到差分后为数组为0。考虑差分。

    差分后数组中有正数,负数和0,题目转化为需使不为0的数变为0的操作数。当然,差分数组的第1和第n+1项除外,因为其跳跃出边界。

    现在,题目中的加1操作变为将左端点(+1),右端点(-1) ,减1操作则恰好相反。

    那么,要使操作最小,我们可以猜测应该使操作两个影响点应尽量在非(1)(n+1)的位置上,也就是都有效。剩余的则只能与(1)(n+1)项配合完成。这个操作显然可以模拟。

    当然,这个解法并不算优,如需更优欢迎移步Luogu

    第一问可以解决了,现在考虑第二问:

    我们将第一个数作为指标,考虑第一个数有多少变化可能。第一个数变化当且仅当操作涉及到第一个数,也就是无法与中间配对的操作(这些操作可以与(1)(n+1)配对,是等价,可互换的)。再加上原来的一个即可。

    上代码

    #include<bits/stdc++.h>
    using namespace std;
    int n,a[100100],c[100100],qp[100100],qf[100100];
    long long ans,sum;
    int main()
    {
    	cin>>n;
    	int hp=1,tp=0,hf=1,tf=0;
    	for (int i=1;i<=n;i++)
    	{
    		cin>>a[i];
    		c[i]=a[i]-a[i-1];
    		if (i==1) continue;
    		if (c[i]>0) qp[++tp]=i;
    		if (c[i]<0) qf[++tf]=i;
    	}
    	sum=1;
    	while (hp<=tp||hf<=tf)
    	{
    		int kp=qp[hp],kf=qf[hf];
    		if (hp>tp) c[kp]=2147483647;
    		if (hf>tf) c[kf]=-2147483647;//不能与2~n配对,那么有可能影响1
    		int v=min(c[kp],-c[kf]);
    		if (c[kp]==2147483647) sum+=-c[kf];
    		if (c[kf]==-2147483647) sum+=c[kp];
    		ans+=v;
                     //可配对情况
    		if (c[kp]>-c[kf])
    		{
    			c[kp]-=v;c[kf]+=v;
    			hf++;
    		}
    		else
    		{
    			if (c[kp]==-c[kf])
    			{
    				c[kp]-=v;c[kf]+=v;
    				hf++;hp++;
    			}
    			else
    			{
    				c[kp]-=v;c[kf]+=v;
    				hp++;
    			}
    		}
    	}
    	cout<<ans<<endl<<sum;
    	return 0;
    }
    
  • 相关阅读:
    python-观察者模式
    python-迭代器模式
    python-策略模式
    python-组合模式
    python-享元模式
    python-代理模式
    虚基类与虚继承
    指针与地址的关系
    大数相加和大数相乘以及打印从1到最大的n位数
    各种排序实现以及稳定性分析
  • 原文地址:https://www.cnblogs.com/fmj123/p/14002506.html
Copyright © 2020-2023  润新知