【第九届蓝桥杯A组国赛】E题题解

前言:

这道题当时看的时候看错了,或者说看得太快,推了一下发现1是1个,2是4个,3就理所当然的认为是9个,然后飞速写完,检查都没检查出来,我也是服了自己。。。说实话确实很伤心,这道题就算是小白,写个暴力,50多分到手,我居然1分都没拿到,优秀奖滚粗也是理所应当的吧。

题目描述:

给一个数列,每一个元素都在G[N]数列中出现G[N]次。

i:    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
G[i]: 1 2 2 3 3 4 4 4 5 5  5  6  6  6  6  7  7  7  7  8
数据规模:
最大为1<N<2*10^16(记不清了,反正在long long范围内)

输入样例:

13

输出样例:

6

解题思路:

这道题由于规模太大,用暴力只能过70%,还要考虑到空间问题。所以我们考虑直接求出N的G[N]肯定会超时。而G[N]可以通过G[G[N]]来求出,所以我们只需要先计算出最近的G[G[N]],每次计算保存N-1的G[N-1],在通过模除G[G[N]]来得出最终的结果。
注意:当所更新的数值的G[G[N]]可以包括的范围大于N或小于0(不知道会不会出现,反正加上)时就不再继续更新,这样优化可以节省极大的时间,测试了10^16的G[N]是9296812705,而9296812705的G[N]是1740381,所以应该是可以过的。所有的数据均采用long long int保存。

源代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#define INF 99999999
#define bug puts("Hello\n")
using namespace std;
int a[10000000]; 
int main(){
    long long int N;
    scanf("%lld",&N);
    a[1]=1;
    a[2]=2;
    long long int i=0,flag=1,tflag=1,cflag=0,pre=1,temp=0,ctemp=0;
    while(1){
        if(temp+a[flag]*flag>N||temp+a[flag]*flag<0)break;
        temp+=a[flag]*flag;
//      printf("%lld\n",temp);
        if(cflag==0)
        for(long long int i=0;i<a[flag];i++){
            if(cflag==0)
            for(long long int j=0;j<flag;j++){
                a[pre]=tflag+i;
                ctemp+=a[pre]*pre;
//              printf("%lld %lld %lld\n",pre,tflag+i,ctemp);
                pre++;
                if(ctemp+a[pre]*pre>N||ctemp+a[pre]*pre<0){
                    cflag=1;
                    break;
                }
            }
        }
        tflag+=a[flag];
        flag++;
//      printf("flag:%lld tflag:%lld\n",flag,tflag);
    }
    long long int now=N-temp,ans;
//  printf("%d\n",now);
    ans=now/flag+tflag;
    if(now%flag==0)ans--;
    printf("%lld\n",ans);
    return 0;
}


猜你喜欢

转载自blog.csdn.net/tjj1998/article/details/80471727
今日推荐