【数学推理】小y的序列

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;
}

有梦想就去努力,因为在这一辈子里面,现在不去勇敢地努力,也许就再也没有机会了

猜你喜欢

转载自blog.csdn.net/zhazhaxiaosong/article/details/105938199