牛客练习赛44 B-小y的线段

题目链接:https://ac.nowcoder.com/acm/contest/634/B
这题是我喜欢的类型——没有复杂的数据结构和算法,只需认真思考,我行,你也行。
思路:没有复杂高深的算法,只需对暴力法优化。

分析:

一.拿到题目,先看数据范围,分析时间复杂度

n的范围是2e7,似乎连O(n)的算法都可能TLE。不过注意到,数据的读入就需要O(n),所以O(n)的算法肯定是可行的。

二.先思考Brute force

这题的Brute force做法显而易见:模拟。双重循环。外循环枚举每个线段i,内循环计算从线段i的0位置到线段n的步数。求和即得答案。不过,在没有优化的情况下,时间复杂度是O(n^2),显然是无法AC的。

三.思考优化方法

既然Brute force是没办法AC的,而这题又似乎也没办法用什么高大上的算法做,我们就只能思考如何优化Brute force。下面我就介绍一下我的思考过程。

1.哪里可以优化?

a.递推是否可行?
由于我们横下心不用什么数据结构和算法,所以优化的方法就比较少了。这一题看上去似乎可以递推,那我们就认真分析一下。
我们模仿数学上的证明过程,先来设置一个引理:当能在O(1)的时间得到从线段i的0位置往下走,第一次被卡住的线段编号,那么我们就能在O(n)的时间用递推得出答案。

很玄学对吧。没关系,我们慢慢证明。令kz[i](卡住ka zhu)表示从线段i的0位置往下走,第一次被卡住的线段编号,根据引理,我们已经将kz数组求出来了。那么,我们就可以递推了。
我们注意到题目中的条件:如果第i+1条线段长度不到j+1,那么就会回到第i条线段的0位置,然后继续跳。也就是说,从第i条线段的0位置往下跳,跳到kz[i]被卡住了,需要返回kz[i]-1行的0位置继续跳。那么从第i条的0位置跳到第n条线段的代价比从kz[i-1]行的0位置跳到第n行的代价多出了kz[i]-i,这个是可以在O(1)的时间求出来的。所以,第i行的代价可以转化为第kz[i-1]行的代价,只不过从第kx[i-1]行的0位置到第n行的代价在求的时候要加倍。我们可以用一个cnt数组来记录遍历到这一行时有几个点同时往下走。所以我们只需一次遍历,就能求出来答案,时间复杂度为O(n)。
理解不了?没关系,配合下面的图,理解起来就方便多了。

递推.png

b.引理如何优化?
虽然推出来了上一步里的递推关系,但是别高兴的太早:上一步的成立是建立在引理成立的基础上。也就是说,我们同样需要在O(n)的时间里求出kz数组。这一步的方法和证明就比较有难度了,希望各位能耐心看下去。

引理证明.png

对于这张图,我们要证明三个结论:
(1)对于任意m,i<m<j,kz[m]>=j;
(2)对于任意k,i<k<=j-a[j]-1,kz[k]=j;
(3)对于任意p,j-a[i]<=p<j,kz[p]>j;

下面证明:
(1)由于kz[i]表示i第一次需要回退一行的编号,所以对于任意m属于(i,j),a[m]>=m-i;所以对于任意t属于(i,m),a[m]>m-t;所以t肯定不被m卡住。对于所以的m,m不被m到j-1的行卡住,即kz[m]>=j。证毕。
(2)由于kz[i]=j,则a[j]<j-i;对于任意k属于(i,j-a[j]-1]],a[j]<j-k,所以kz[k]<=j,又由(1)得知kz[k]>j-1,所以kz[k]=j;
(3)由于a[j]>j-p,又由(1)知,kz[p]>j,所以kz[p]>j;

现在,证明完毕,我也可以介绍我的做法了。
首先,我们将kz数组赋值为无穷大,从i=nxt到n遍历一遍,nxt初始为1,维护下次开始遍历的位置。每次从nxt开始往下找到第一个会卡住的位置j。则从任意k属于[nxt,j-a[j]-1],kz[k]=j;nxt=j-a[j];
然后,再一次倒序遍历,若kz[i]!=无穷大,则将所有i到下一个kz[j]!=无穷大的j,任意k属于[j,i],kz[k]=kz[i];即可得kz数组。

至此,两个优化均完成,且总时间复杂度为O(n),最后提醒的是,注意用long long int 记录答案。于是,AC!
代码如下:


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<cstring>
#include<cstdlib>

using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int maxn=2e7+5;
const int INF=0x3f3f3f3f;
unsigned int SA, SB, SC,a[maxn];
int mod,n;
int kz[maxn],cnt[maxn];
ll ans=0;
unsigned int Rand() {
    SA ^= SA << 16;
    SA ^= SA >> 5;
    SA ^= SA << 1;
    unsigned int t = SA;
    SA = SB;
    SB = SC;
    SC ^= t ^ SA;
    return SC;
}
int main() {
    ios::sync_with_stdio(false);
    freopen("小y的线段.in","r",stdin);
    cin>>n>>mod>>SA>>SB>>SC;
    for(int i = 1; i <= n; ++i) 
    { 
        a[i] = Rand() % mod + 1;
        kz[i]=-INF;
        cnt[i]=1;
    } 
    int i=1;
    a[n+1]=0;
    bool needxg=true;
    int nxt=2;
    while(i<=n)
    {
        int j=nxt;
        for(;j<=n+1;j++)
        {
            if(j-i>a[j])//i kazhu
            {
                kz[j-a[j]-1]=j;
                i=j-a[j];
                nxt=j+1;
                break;
            }
        }
    }
    int temp;
    for(int j=n;j>=1;j--)
    {
        if(kz[j]!=-INF)
            temp=kz[j];
        else
            kz[j]=temp;
    }

    for(int i=1;i<=n;i++)
    {
        if(kz[i]>n) continue;
        ans+=((ll)kz[i]-i)*cnt[i];
        cnt[kz[i]-1]+=cnt[i];
    }
    for(int i=1;i<=n;i++){
        if(kz[i]>n){
            ans+=(ll)(n-i)*cnt[i]; 
        }
    }
    cout<<ans<<endl;
    return 0;
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容

  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,340评论 0 2
  • <center>#1 Two Sum</center> link Description:Given an arr...
    铛铛铛clark阅读 2,145评论 0 3
  • 动态规划(Dynamic Programming) 本文包括: 动态规划定义 状态转移方程 动态规划算法步骤 最长...
    廖少少阅读 3,279评论 0 18
  • 每年秋天开始降温的时候,总是会刮起大风,南方街道两旁的行道树,开始大片大片的掉叶子,尽管树叶还没有枯黄。风一起,萧...
    七分白阅读 303评论 3 3
  • 在前些日子,我第一次做了手术。这个手术花费了两个半小时这样。在手术前一天,我就特别的紧张。在心里甚至还想放弃,放弃...
    帅哥的哥哥的哥阅读 149评论 0 0