UPC 2020年春混合个人训练 5.4日场
时间限制: 1 Sec 内存限制: 128 MB
题目描述
又是一年 NOIP,高中机房的学长们都在做题,安静的有点可怕,突然听到隔壁机房某老师熟悉的声音:“我们看一下这道题,找找规律发现这个序列很熟悉啊,就是2,3,5,7,12这其实就是一个a[i+1]-a[i]=i的序列哦,突然隔壁的吵闹声大了起来,老师,老师好像有个数写错了(大雾)~~~~~~~~~~~~
课后,小y大牛跑到隔壁机房在黑板上写下了这个题目,让小朋友们做:给出一个长度为n的整数序列a,你能改动最少的数,使之满足a[i+1]-a[i]=i吗?1<=i<n。
输入
第一行一个整数n;
第二行包含n个整数(每两个数之间有一个空格),分别表示a[1]到a[n]。
输出
输出一个整数,表示最少改多少个数
样例输入
5
1 2 4 5 11
样例输出
1
提示
对于30%的数据 n<=1000
对于100%的数据 n<=100000
输入的其他数据的绝对值均小于等于1E9
解题思路:当把一个数确定后,这个数列也就是确定的了,那么可以把每个数对应的一个数分别求出来(这里是以a[n]为标准来求每个数应该对应的a[n]),要求改动最小的次数,用n减掉那个出现最多的次数就ok了,接下来就是推理的过程(在代码中),由于本题下标达到了1e9,用map记录次数就没啥问题了
AC源:
/**
推理ing:
由题意得:
a[n]-a[n-1]=n-1;
a[n-1]-a[n-2]=(n-1)-1;
a[n-2]-a[n-3]=(n-1)-2;
......
a[2]-a[1]=(n-1)-(n-2);
移项,得:
a[n]=a[n-1]+(n-1);
a[n]=a[n-2]+2*(n-1)-1;
a[n]=a[n-3]+3*(n-1)-3;
......
a[n]=a[1]+(n-1)*(n-1)-vis[n-2] ///这里的vis是用来打表用的,很容易就会发现最后一个数的规律
最后得到求a[n]的通项公式为a[n]=a[i]+(n-i)*(n-1)-vis[n-i-1];
**/
#include<bits/stdc++.h>
#include<vector>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const int maxn = 1e6+7;
typedef pair<int,int> PII;
map<ll,ll>mp;
PII q[100000];
ll n;
ll a[maxn],vis[maxn];
int main(){
ll flag=1,maxx=0;
scanf("%lld",&n);
for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
for(ll i=1;i<=n;i++) vis[i]=vis[i-1]+flag,flag++; ///打表
///for(ll i=1;i<=10;i++) cout << vis[i] << endl;
for(ll i=n;i>=1;i--)
{
if(i==n)
{
mp[a[i]]++;
maxx=max(maxx,mp[a[i]]);
}
else{
ll temp=a[i]+(n-i)*(n-1)-vis[n-i-1];
///cout << temp << endl;
mp[temp]++;
maxx=max(maxx,mp[temp]); ///每次取max
}
}
cout << n-maxx << endl;
return 0;
}
有梦想就去努力,因为在这一辈子里面,现在不去勇敢地努力,也许就再也没有机会了