您的位置:首页 > 运维架构

CF D. Population Size(贪心+模拟)

2014-04-16 11:47 411 查看
http://codeforces.com/problemset/problem/416/D

题意:给出n个数,其中包含正整数和-1,-1可代表任意正整数(必须大于0)。问n个数可以最少划分为多少个等差数列。

思路:贪心。让当前的数尽量属于前一个等差数列。用fir和sec维护两个连续的确定的数,并用arb维护fir前面可能属于该等差数列的第一个-1的位置。当fir和sec确定一个公差d后,要保证fir前面-1的位置是正整数,否则fir和sec之间的数分别属于两个等差序列。fir与sec依次后移,重复上述操作。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define LL long long
#define _LL __int64
using namespace std;

const int maxn = 200010;

int a[maxn],n,ans;

int main()
{
	while(~scanf("%d",&n))
	{
		for(int i = 1; i <= n; i++)
			scanf("%d",&a[i]);
		ans = 0;
		bool fir = false,sec = false; //表示一个等差序列的前两个确定的数的布尔变量
		int arb = -1;//标记该等差数列下fir前面的第一个-1的位置,初始化为-1说明当前等差数列没有前导的-1
		int d,pre = -1;//pre保存前一个确定的数
		
		for(int i = 1; i <= n; i++)
		{
			if(a[i] > 0)
			{
				if(!fir)	
					fir = true;	//标记第一个数出现
				else if(!sec)
				{
					if( (a[i] - a[pre]) % (i-pre) )	//当前数a[i]与前一个确定的数不能构成一个等差数列,那么划分为两个
					{
						arb = -1; //划分为两个后,第二个等差数列前面不会有-1,所以arb置为-1。
						ans++;
					}
					else
					{
						d = (a[i]-a[pre]) /(i-pre);
						if(arb == -1 || a[i]-1LL*(i-arb)*d > 0) //若当前等差数列前面有-1就计算-1的位置是否可能 <= 0
							sec = true;
						else
						{//若 <= 0,也划分成两个数列
							ans++;
							arb = -1;
						}
					}
				}

				else
				{
					if(a[i] - a[pre] != 1LL*(i-pre)*d )//判断a[i]是否能加到前面的数列中
					{
						ans++;
						sec = false;
						arb = -1;
					}
				}

				pre = i;

			}

			else
			{
				if(sec && a[pre] + 1LL*(i-pre)*d <= 0) //若-1不能加到前面的数列中,就开一个新的数列
				{
					fir = false;
					sec = false;
					ans++;
					arb = i;
				}
				else if(arb == -1)
					arb = i;
			}

		}
		printf("%d\n",++ans);
	}
	return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: