初三奧賽模擬測試1

卡布叻_周深發表於2024-03-11

前言

  • 比賽連結

  • 總分:\(107pts\)

    image

  • \(T1~79pts:\)

    座標 \(DP\) ,賽時感覺打的是正解,但是打假了。

  • \(T2~28pts:\)

    理解錯題了,以為是幫他調程式了,於是給人家調 \(TLE\) 了。

  • \(T3~0pts,T4~0pts:\)

    沒啥好說的,不會。

  • 官方題解

T1 迴文

點選檢視題面

image

  • 部分分:

    部分分沒什麼好說的,大多集中在 \(79pts\) ,都是 \(DP\) 打假了的。

  • 正解:

    座標 \(DP\)

    \(4\) 維的很好想,對於迴文串的性質,從前往後跑和從後往前跑路徑是一樣的。

    那麼定義 \(f[i][j][k][l]\) ,表示從前往後跑到 \(a[i][j]\) ,從後往前跑到 \(a[k][l]\) 時的方案數。

    但是 \(4\) 維肯定會 \(MLE\) ,之後發現第 \(4\) 維可以去掉,因為從前往後和從後往前跑路徑始終是保持相同的,所跑的步數也一定是相同的,那麼第 \(4\)\(l\) 完全可以用 \(i,j,k\) 表示。

    • 解釋一下:

      \(a[1][1]\) 跑到 \(a[n][m]\) ,需要走的步數為 \(n+m-1\) ,起點不算,那麼均分下來,兩邊各需跑 \(maxx=\dfrac{n+m-1}{2}\) 步。

      那麼對於從前往後的步數顯然為 \(i+j-1\) ,起點不算,那麼從後往前搜走的步數也一定是 \(i+j-1\) ;對於從後往前的步數同樣的可以表示為 \((n-k+1)+(m-l+1)-1=i+j-1\) ,那麼 \(l=m+n-i-j-k+2\)

    所以定義 \(f[i][j][k]\) 即可,第 \(4\) 維不是消失了,是可以用前 \(3\) 維表示,不需要存了。

    轉移方程很好想,如果 \(a[i][j]=a[k][l]\) ,那麼對於其下一步 \(f[i1][j1][k1]+=f[i][j][k]\) 即可。當然對於此時如果 \(i+j-1=maxx\) ,也就是已經匹配完了,就不需要轉移了。

    不好搞的是統計答案。

    發現 \(m+n\) 奇偶不同時,統計答案也是不同的,若 \(n+m\) 為奇數時,他兩邊同時跑最後時到達一個點的;反之為偶數時,他最後會跑到相鄰的兩個點。

    如圖:

    1. \(m+n\) 為奇數

      image

      討論到達 \(ans\) 的前一刻 \(k,l\) 可能的位置,如圖 \(1,2\) ,所以對於 \(k\) 的位置可能為 \(i,i+1\)\(l\) 的位置不用討論,\(k\) 確定同時也就確定了。

    2. \(m+n\) 為偶數

      image

      討論 \(k,l\) 在到達 \(ans2\) 上一步時可能的位置,如圖 \(1,2,3\) ,同時注意 \(2\) 的貢獻有兩次,所以要家兩次。所以 \(k\) 的位置可能為 \(i,i+1,i+2\) ,其中 \(i+1\) 的情況要算兩遍。

    而至於 \(\%\) 的常數很大,可以打一個 \(mod\) 函式,看程式碼就知道了。

    點選檢視程式碼
    #include<bits/stdc++.h>
    // #define int long long 
    #define endl '\n'
    using namespace std;
    const int N=510,P=993244853;
    template<typename Tp> inline void read(Tp&x)
    {
        x=0;register bool z=true;
        register char c=getchar();
        for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
        for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
        x=(z?x:~x+1);
    }
    int n,m,maxx;
    unsigned int f[N][N][N],ans;
    char a[N][N];
    int hx[5]={0,1,1,0,0},zx[5]={0,0,0,1,1},hy[5]={0,-1,0,-1,0},zy[5]={0,0,-1,0,-1};
    void mod(unsigned int &x) {x=(x>=P?x-P:x);}
    signed main()
    {
        #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
        #endif
        read(n),read(m);
        maxx=(n+m-1)/2;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                cin>>a[i][j];
        if(a[1][1]!=a[n][m]) 
        {
            cout<<0;
            return 0;
        }
        f[1][1][n]=1;
        for(int i=1;i<=n;i++)
            for(int j=1;i+j<=maxx+1&&j<=m;j++)
                for(int k=n;k>=i;k--)
                {
                    int l=m+n-i-j+2-k;
                    if(a[i][j]==a[k][l])
                    {
                        if(i+j!=maxx+1)
                            for(int x=1;x<=4;x++)
                            {
                                int i1=i+hx[x],j1=j+zx[x],k1=k+hy[x],l1=l+zy[x];
                                if(a[i1][j1]==a[k1][l1])
                                    f[i1][j1][k1]+=f[i][j][k],mod(f[i1][j1][k1]);
                            }
                    }
                }
        if(!((m+n)&1)) 
            for(int i=1;i<=min(n,maxx);i++)
            {
                for(int k=0;k<=2;k++)
                    {
                        int j=maxx-i+1;
                        ans+=f[i][j][i+k],mod(ans);
                    }
                ans+=f[i][maxx-i+1][i+1],mod(ans);
            }   
        else 
            for(int i=1;i<=min(n,maxx);i++)
                for(int k=0;k<=1;k++)
                {
                    int j=maxx-i+1;
                    ans+=f[i][j][i+k],mod(ans);
                }
        cout<<ans;
    }
    

    複雜度 \(O(n\times m\times n)\)

T2 快速排序

點選檢視題面

image

  • 部分分:

    直接在給的快排函式上調,他那個程式碼時沒有隨機化的,會 \(TLE\) 的,所以我 \(TLE~28pts\) ,別人多少不知道了。

  • 正解:

    首先他那個快排是死的,我們自帶的 \(stable\_sort\) 是有隨機化的,直接用這個即可。

    然後分析他這個程式碼(分析樣例)。

    對於當前位置如果是 \(nan\) 的話,就不動,直接輸出。

    否則,就將所有比他小的數,包括他自己輸出即可,當然輸出過的就不再輸出了。

    思路聽起來很簡單的,調程式碼就行了。

    實現就比較簡單了,每個人方法可能不一樣,直接看程式碼吧。

    點選檢視程式碼
    #include<bits/stdc++.h>
    #define int long long 
    #define endl '\n'
    using namespace std;
    const int N=5e5+10;
    template<typename Tp> inline void read(Tp&x)
    {
        x=0;register bool z=true;
        register char c=getchar();
        for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
        for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
        x=(z?x:~x+1);
    }
    int t,n,b[N],tot,id[N];
    string a[N];
    bool v[N];
    signed main()
    {
        #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
        #endif
        read(t);
        while(t--)
        {
            tot=0;
            memset(v,0,sizeof(v));
            memset(id,0,sizeof(id));
            memset(b,0,sizeof(b));
            read(n);
            for(int i=1;i<=n;i++)
            {
                cin>>a[i];
                if(a[i]=="nan") continue;
                int s=0;
                for(int j=0;j<a[i].size();j++)
                    s=s*10+a[i][j]-'0';
                b[++tot]=s,id[i]=b[tot];
            }
            stable_sort(b+1,b+1+tot);
            int j=0;
            for(int i=1;i<=n;i++)
            {
                if(a[i]=="nan")
                {
                    cout<<a[i]<<' ';
                    continue;
                }
                else 
                {
                    if(j==tot||b[j]>id[i]) continue;
                    while(++j)
                    {
                        if(b[j]) cout<<b[j]<<' ';
                        if(b[j]==id[i]||j==tot) break;
                    }
                }
            }
            cout<<endl;
        }
    }
    

    複雜度 \(O(n\log(n))\) ,帶一定的常熟(將字串轉換為整型)。

相關文章