1. 程式人生 > 實用技巧 >關於重複定義變數與memset函式導致超時的分析

關於重複定義變數與memset函式導致超時的分析

簡述

先上倆組程式碼
code1:

void solve(){
    int n;
    PII a[200010];//注意此處
    cin>>n;
    rep(i,1,n){
        cin>>a[i].fi;
        a[i].se=i;
    }
    sort(a+1,a+1+n);
    a[n+1].fi=INF;
    a[0].fi=INF;
    int k;
    rep(i,1,n){
        if(a[i].fi!=a[i-1].fi&&a[i].fi!=a[i+1].fi){
            cout<<a[i].se<<endl;
            return;
        }
 
    }
    cout<<-1<<endl;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

code2:

void solve(){
    int n;
    n=read();
    PII a[n+10];//注意此處
    rep(i,1,n){
        a[i].fi=read();
        a[i].se=i;
    }
    sort(a+1,a+1+n);
    a[n+1].fi=INF;
    a[0].fi=INF;
    int k;
    rep(i,1,n){
        if(a[i].fi!=a[i-1].fi&&a[i].fi!=a[i+1].fi){
            write(a[i].se);
            printf("\n");
            return;
        }
 
    }
    cout<<-1<<endl;
}
int main(){
    int t;
    t=read();
    while(t--){
        solve();
    }
    return 0;
}

顯然上面倆組程式碼只有註釋處不同,我們將其拿到cf上交倆發

code1耗時

code2耗時

倆個程式碼耗時竟然相差了十倍!!!!!!!

分析

當輸入資料為\(t=2e4\),
接下來跟著\(2e4\)
\(n=3\)
\(a_1=1,a_2=1,a_3=1\)
每次while迴圈中會重複定義一個2e5的陣列a,此處的a顯然為區域性變數,眾所周知區域性變數會在本次執行完成後進行銷燬操作,可能是此處的申請空間與銷燬空間耗時太多,導致時間花費較大,具體的情況筆者也不瞭解,此為猜測,不太懂編譯原理相關的東西.


再來看看定義一個\(2e5\)大小的全域性變數,每次在\(solve\)中使用memset(a,0,sizeof a)

清空,此時memset幾乎等價於for(int i=1;i<=2e5;i++) a[i]=0,當輸入上面的資料時,時間複雜度為

\[O(1e4*1e5)=1e9 \]

顯然\(c++\)一秒內是跑不完的,導致超時

使用memset的解決方案:
memset(a,0,sizeof a)換成for(int i=1;i<=n;i++) a[i]=0即可

此時依舊執行上面的樣例,時間複雜度為\(O(2e4*3)\),顯然很快


記錄一場cf被hack的經歷
本來的code1為cin/cout輸入輸出,直接被某同學當場hack掉

code1為加入快讀版本,在cf選手的不斷努力下從800+ms跑到998ms,極限ac

珍愛\(rating\),避免不好的程式碼習慣(大霧)