codechef Chef and sequence

Problem Description

You are given an array that consists of n integer numbers. You have to change at most K elements of this array, so that the resulting array will be a arithmetic progression. From all the possible arithmetic progressions, you should choose most beautiful.
You can uniquely define the arithmetic progression by two numbers a0 and d - the first element of the given progression and the step that defines next element. (ai = a0+i * d). The progression A(a0 , d0) is more beautiful than the progression B(b0, d1) iff (a0 < b0 or (a0 = b0 and d0 < d1))

Input

The first line contains two integers N and K denoting the number of elements in the given array and the number of elements that you can change
The second line contains N space-separated integers A1, A2, ..., AN denoting the given array.

题目大意:

给你一个长度为n的序列,要你改动至多K个数,使之变为等差数列,我们用一个式子描述改变后的数列:ai=a0+i*d。要求改动后使a0尽量小,a0相同时d尽量小。

输出改动后的数列。

Output

Output a single line containing the resulting array with at most K changes. Mind that among all the arithmetic sequences you have to choose the most beautiful.
In the given test data, it is always possible to recover at least one arithmetic progression under the constraints of the problem.

Constraints

2 ≤ N ≤ 100000
0 ≤ K ≤ min(10, N-2)
-109 ≤ Ai ≤ 109

Example

Input:
4 2
1 2 1 4

Output:
-5 -2 1 4

题解

这道题怪怪的,感觉codechef上的不少题想法都怪怪的。感谢lwher的思路。

K最多只有10个,意味着原数列已经很接进答案了——在n较大的情况下,我们随机抓两个数,很可能得到最终的a0和d(因为这两个数很有可能是不需要改动的),而在n较小的情况下,也一定保证至少有两个数不需要改动。

所以我们只要枚举前23位(其实13就够了,因为最多只改十个),选出两个数算出a0和d,带回原数组检验是否有<=K个数不满足ai的表达式即可。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
int n,m,a[100002];
ll ansa=1<<30,ansd=1<<30;
void init()
{
	scanf("%d%d",&n,&m);
	int i;
	for(i=1;i<=n;i++) scanf("%d",&a[i]);
}
void work1()
{
	int i,j,k,w,ct;
	ll t,d,a0;
	for(i=1;i<n;i++)
	for(j=i+1;j<=n;j++)
	   {t=a[j]-a[i]; w=j-i;
	    if(t%w!=0) continue;
	    d=t/w; a0=a[i]-i*d;
	    ct=0;
	    for(k=1;k<=n;k++)
	       {if(a[k]!=a0+k*d) ct++;
		    if(ct>m) break;
		   }
		if(ct<=m)
		   {if(ansa>a0)
		       {ansa=a0; ansd=d;}
		    else if(ansa==a0&&ansd>d) ansd=d; 
		   }
	   }
	for(i=1;i<n;i++)
	   printf("%lld ",ansa+i*ansd);
	printf("%lld\n",ansa+n*ansd);
}
void work2()
{
	int i,j,k,w,ct;
	ll t,d,a0;
	for(i=1;i<23;i++)
	for(j=i+1;j<=23;j++)
	   {t=a[j]-a[i]; w=j-i;
	    if(t%w!=0) continue;
	    d=t/w; a0=a[i]-i*d;
	    ct=0;
	    for(k=1;k<=n;k++)
	       {if(a[k]!=a0+k*d) ct++;
		    if(ct>m) break;
		   }
		if(ct<=m)
		   {if(ansa>a0)
		       {ansa=a0; ansd=d;}
		    else if(ansa==a0&&ansd>d) ansd=d; 
		   }
	   }
	for(i=1;i<n;i++)
	   printf("%lld ",ansa+i*ansd);
	printf("%lld\n",ansa+n*ansd);
}
int main()
{
	init();
	if(n<=22) work1();
	else work2();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值