码迷,mamicode.com
首页 > 其他好文 > 详细

[CodeForces 416D]Population Size

时间:2018-06-16 14:31:38      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:并且   最优   公式   不能   clu   names   暴力   pac   cin   

Translate:

给定一个序列,\(-1\)可以被替换成任意正整数,求该序列最少可以被分成多少个等差数列.(注意:分成的是子串而不是子序列)

一道比较难的贪心题。我们首先要整理:

  • 等差数列的性质:指从第二项起,每一项与它的前一项的差等于同一个常数的一种数列

  • 求公差的公式:开头与结尾的数的差\(/\)有几个数

根据题意,可以初步整理:

  • 既然全部的数都是正整数,那么等差数列的公差一定要是整数,即不能为小数

  • 只有一个已知数或者没有已知数答案是\(1\)

  • 既然有\(-1\)干扰,我们一定要找两个确定的数去求等差数列,并且让\(-1\)一定要尽量最优

  • 假设这\(2\)个数为\(left\)\(right\),那么有right之前的数组成等差数列(不包括right),与right为left与一个新的right(在旧的right的右边)组成一个新的等差数列.

思路:

从上一个等差数列的结尾加一处开始找两个非-1的数,算出公差。如果公差为小数或者该公差导致前面的一串-1中有可能会有数变成非正数,就将第一个非-1的数和前面的一堆-1和两数间的一堆-1作为第一个数列,再以第二个非-1的数开头找等差数列。否则就再向后找可以合并到这个等差数列的数加入这个数列,找不到了就从这个等差数列的结尾加一处再找等差数列。

那么以上内容如何处理我会在代码注释说明

Code

#include <bits/stdc++.h>
using namespace std;
int a[200000+15];
int main()
{
    int n,now,left,right,k,ans=0;
    //now是记录当前处理到哪里了,当然下面那个读入不算
    //left和right如解释
    //ans记录答案,k一会你们就知道了
    cin>>n;
    for(now=1; now<=n; ++now)
        scanf("%d",&a[now]);
    bool is=0;
    long long cur,diff;//diff是公差,cur一会你们就知道了QAQ
    now=1;
    while(now<=n)//如果没处理完就继续
    {
        ++ans;//没次ans+1
        //下面的代码是找到2个非-1的数,很好理解
        for(left= now; left<=n; ++left)
            if(a[left]!=-1)
                break;
        for(right=left+1; right<=n; ++right)
            if(a[right]!=-1)
                break;
        if(right>n)//right>n代表着right=n+1,即为只有1个整数或者没有整数,就直接推出ok
            break;
        diff= (a[right]-a[left])/(right-left);//公差公式
        if(a[right]!=a[left]+ (right-left)*diff)
        {
            now= right;
            continue;
        }
        /*
        以上是判断公差是否为小数的
        - 因为diff是long long,小数会自动转换(向下取整),所以就一定会有误差
        - 然后如果他左边的是-1,因为-1最优,所以将他左边的数作为1个等差数列,下一次剩下的这个整数right再次处理即可
        - 如果是整数,那么这个整数左边肯定有-1或没有-1,那么就同上了
        */
        cur = a[left]-diff*(left-now);
        //cur代表求出公差会让最前面的正整数变成什么数
        if(cur<=0)
        {
            now=right;
            continue;
        }//如果变成非正数了,同上处理
        
        //否则这个等差数列算上right,而且这个等差序列也可能继续往下
        
        cur = a[right++]+diff;
        //cur又摇身一变变成基准数啦(不要误会这个词语,是计算下一个数如果能算进等差数列的话应该是几)
        while(right<=n)//暴力往下走
        {
            if(cur<=0)//如果变成非正数照样处理
                break;
            if(a[right]!=-1)//因为-1是最优值,所以不需要处理
            {
                if(a[right]!=cur)//当前的数不等于cur,代表错了哦
                    break;
            }
            ++right;
            cur+=diff;//别忘了更新基准数
        }
        now= right;//更新
    }
    cout<<ans<<endl;//输出答案
    return 0;
}

[CodeForces 416D]Population Size

标签:并且   最优   公式   不能   clu   names   暴力   pac   cin   

原文地址:https://www.cnblogs.com/lyfoi/p/9190327.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!