每日卡常小技巧

· · 个人记录

密码是图片链接。

前言

常数,真的是一个非常可怕的东西。它看似微小至极,在众多的复杂度分析中被一句 O(1) 一笔带过,但它可以带来的改变,是无止境的。

拥有小常数是一件非常值得夸耀的事情,你可以 1e9 过 1s,可以随便爆踩 std,甚至可以高高在上地看着同机房的同学们深深陷入卡常的痛苦深渊中。

相反,拥有大常数则非常的骇人听闻。O(n \log n) 跑得没有别人的 O(n \log^2 n) 快,有时交了十遍二十遍,调了无数的块长也不能 A 掉一道题,再者,卡常卡一晚上也卡不出个结果。

在当今这个大家都很强的 OI 界中,不是卡常,就是被卡常,谁会错过如此的大好机会?如果在比赛时因为常数挂了分,如果打 CF 时因为常数喜提 -50,如果打 AT 时因为常数吃了一发罚时,影响是不可估量的。

而这个时候,拥有小常数,即卡常的优势就显现出来了。养成了良好的卡常习惯,你也可以从一名大常数 OIer 变成一名和我完全相反的小常数 OIer,而这篇每日卡常小技巧就是为此所做。

正文

实战小练习

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,k,q,a[1200005],dp[2][1200005],Q[1200005],cnt[2],Ans[1200005],d[1200005],Temp[2],vis[2][1200005];
struct node{
    int l,r,id;
}A[600005],Q1[600005],Q2[600005];
struct Point{
    int x,y;
}P[600005];
inline void BFS(int xa,int ya,int xb,int yb,int x,int y,int id){
    if(id==0){
        int Max=min(n,yb*k+xb),now=y*k+x;
        dp[0][now]=0;
        Temp[0]++;
        vis[0][now]=Temp[0]; 
        for(int i=now+1;i<=Max;++i){
            dp[0][i]=-9999999999999999ll;
            vis[0][i]=Temp[0];
            if(i-k>=now){
                dp[0][i]=max(dp[0][i],dp[0][i-k]+Q[i]-Q[i-k]);
            }
            dp[0][i]=max(dp[0][i],dp[0][i-1]);
        }
    } 
    else{
        int Min=ya*k+xa,now=y*k+x;
        dp[1][now]=0;
        Temp[1]++;
        vis[1][now]=Temp[1];
        for(int i=now-1;i>=Min;--i){
            dp[1][i]=-9999999999999999ll;
            vis[1][i]=Temp[1];
            if(i+k<=now){
                dp[1][i]=max(dp[1][i],dp[1][i+k]+Q[i+k]-Q[i]);
            }
            dp[1][i]=max(dp[1][i],dp[1][i+1]); 
        }
    }
    return;
} 
inline bool Check(Point A,Point a,Point b){
    if(a.x<=A.x&&A.x<=b.x&&a.y<=A.y&&A.y<=b.y){
        return true;
    }
    return false;
}
void Solve(int xa,int ya,int xb,int yb,int L,int R,bool Flag){//(x,y)->(ID:yk+x)
    int Lenx=xb-xa+1,Leny=yb-ya+1,Mid;
    if((xa>xb)||(ya>yb)||(xa==xb&&ya==yb)||L>R){
        return;
    }
    if(Lenx<Leny){
        Mid=(ya+yb)>>1;
        for(int i=xa;i<=xb;++i){
            int x=i,y=Mid,ID=y*k+x;
            if(ID>n){
                break;
            }
            BFS(xa,ya,xb,yb,x,y,0);//原图 
            BFS(xa,ya,xb,yb,x,y,1);//反图 
            for(int j=L;j<=R;++j){
                if((!Check(P[A[j].l],Point{xa,ya},Point{xb,yb}))||(!Check(P[A[j].r],Point{xa,ya},Point{xb,yb}))){
                    continue;
                }
                if((vis[1][A[j].l]!=Temp[1])||(vis[0][A[j].r]!=Temp[0])){
                    continue;
                }
                Ans[A[j].id]=max(Ans[A[j].id],dp[1][A[j].l]+dp[0][A[j].r]);
            }
        }
        int cnt1=0,cnt2=0;
        for(int j=L;j<=R;++j){
            if(P[A[j].l].y<=Mid&&P[A[j].r].y<=Mid){
                ++cnt1;
                Q1[cnt1]=A[j];
            }
            else if(P[A[j].l].y>Mid&&P[A[j].r].y>Mid){
                ++cnt2;
                Q2[cnt2]=A[j];
            }
        }
        for(int i=L;i<=L+cnt1-1;++i){
            A[i]=Q1[i-L+1];
        }
        for(int i=R-cnt2+1;i<=R;++i){
            A[i]=Q2[i-R+cnt2];
        }
        Solve(xa,ya,xb,Mid,L,L+cnt1-1,Flag);
        Solve(xa,Mid+1,xb,yb,R-cnt2+1,R,Flag);
    } 
    else{
        if(!Flag){
            for(int i=ya;i<yb;++i){
                BFS(xa,ya,xb,yb,0,i+1,0);
                BFS(xa,ya,xb,yb,k-1,i,1);
                for(int j=L;j<=R;j++){
                    if((!Check(P[A[j].l],Point{xa,ya},Point{xb,yb}))||(!Check(P[A[j].r],Point{xa,ya},Point{xb,yb}))){
                        continue;
                    }
                    if((vis[1][A[j].l]!=Temp[1])||(vis[0][A[j].r]!=Temp[0])){
                        continue;
                    }
                    Ans[A[j].id]=max(Ans[A[j].id],dp[1][A[j].l]+dp[0][A[j].r]); 
                } 
            } 
        }
        Flag=true; 
        Mid=(xa+xb)>>1;
        for(int i=ya;i<=yb;++i){
            int x=Mid,y=i,ID=y*k+x;
            if(ID>n){
                break;
            } 
            BFS(xa,ya,xb,yb,x,y,0);
            BFS(xa,ya,xb,yb,x,y,1); 
            for(int j=L;j<=R;++j){
                if((!Check(P[A[j].l],Point{xa,ya},Point{xb,yb}))||(!Check(P[A[j].r],Point{xa,ya},Point{xb,yb}))){
                    continue;
                }
                if((vis[1][A[j].l]!=Temp[1])||(vis[0][A[j].r]!=Temp[0])){
                    continue;
                }
                Ans[A[j].id]=max(Ans[A[j].id],dp[1][A[j].l]+dp[0][A[j].r]);
            }
        }
        int cnt1=0,cnt2=0;
        for(int j=L;j<=R;++j){
            if(P[A[j].l].x<=Mid&&P[A[j].r].x<=Mid){
                ++cnt1;
                Q1[cnt1]=A[j];
            }
            else if(P[A[j].l].x>Mid&&P[A[j].r].x>Mid){
                ++cnt2;
                Q2[cnt2]=A[j];
            }
        }
        for(int i=L;i<=L+cnt1-1;++i){
            A[i]=Q1[i-L+1];
        }
        for(int i=R-cnt2+1;i<=R;++i){
            A[i]=Q2[i-R+cnt2];
        } 
        Solve(xa,ya,Mid,yb,L,L+cnt1-1,Flag);
        Solve(Mid+1,ya,xb,yb,R-cnt2+1,R,Flag);
    }
    return;
}
namespace IO
{
    #define SIZE (1<<24)
    char in[SIZE],out[SIZE],*p1=in,*p2=in,*p3=out;
    #define getchar() (p1==p2&&(p2=(p1=in)+fread(in,1,SIZE,stdin),p1==p2)?EOF:*p1++)
    #define flush() (fwrite(p3=out,1,SIZE,stdout))
    #define putchar(ch) (p3==out+SIZE&&flush(),*p3++=(ch))
    template<typename type>
    inline void read(type &x)
    {
        x=0;bool flag(0);char ch=getchar();
        while(!isdigit(ch)) flag^=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        flag?x=-x:0;
    }
    template<typename type>
    inline void write(type x,bool flag=1)
    {
        x<0?x=-x,putchar('-'):0;static short Stack[50],top(0);
        do Stack[++top]=x%10,x/=10;while(x);
        while(top) putchar(Stack[top--]|48);
        flag?putchar('\n'):putchar(' ');
    }
    #undef SIZE
    #undef getchar
    #undef putchar
    #undef flush
}using namespace IO;
int main(){
//  freopen("t.in","r",stdin);
//  freopen("a.out","w",stdout); 
    read(n);
    read(k);
    read(q);    
    for(int i=1;i<=n;++i){
        read(a[i]);
        P[i].x=i%k;
        P[i].y=i/k;
        Q[i]=Q[i-1]+a[i];
    }
    for(int i=1;i<=q;++i){
        read(A[i].l);
        read(A[i].r);
        --A[i].l;
        A[i].id=i;
    }
    Solve(0,0,k-1,n/k,1,q,false);
    for(int i=1;i<=q;++i){
        write(Ans[i],1); 
    }
    fwrite(out,1,p3-out,stdout);
    return 0;
}

这是 Just_int_mian 在 P9040 [PA2021] Desant 2 一题的次优解???代码。不是,怎么就变成次优解了?被学长给卡得比我还快了。

不管了,你的任务是将这份代码卡到 500 ms 以下,然后发给 Just_int_mian 以领取神秘奖励一份。

神秘奖励:帮你造数据。

实战小练习 1 已经有人快要完成了。太强了。