1. 程式人生 > >洛谷 P2481 [SDOI2010]代碼拍賣會

洛谷 P2481 [SDOI2010]代碼拍賣會

都是 bit 意義 tex long long bits 根據 很快 efi

洛谷

這大概是我真正意義上的第一道黑題吧!

自己想出了一個大概,狀態轉移方程打錯了一點點,最後還是得看題解。

一句話題意:求出有多少個\(n\)位的數,滿足各個位置上的數字從左到右不下降,且被\(p\)整除。

剛開始沒有看到數位不下降這個條件,於是自信滿滿的喊了一句:“這是假黑題吧!”

後來發現了,想了好久好久才找到一條規律。。。

對於任意一個\(n\)位的數,因為要求滿足數位不下降,所以一定可以拆分成\(0,1,11,111,1111,11111……\)的和。

又因為數字最大是\(9\),所以就是從上述數字中任選\(9\)個的和。

於是,我敏銳的覺察到,這是一個dp題,嘿嘿~

分析了一下,由於\(n\)

實在太大\((n\leq10^{18})\)所以時間復雜度肯定要去掉這個\(n\)

然後,我們又會發現\(p\)的範圍很小很小,只有\(500\),於是我們很快想到模數的循環之類的。

因為這裏的所有數都是由\(0,1,11,111,1111,11111……\)組成的,又因為這些\(1\)們模上\(p\)會出現循環。

所以我們記\(cnt[i]\),表示模\(p\)\(i\)的這些11111……

顯然我們需要預處理一波\(cnt[]\)數組,直接從\(1\)枚舉到\(p\)即可。

有了上面這些性質,就很好能想出如何定義狀態了。

\(f[i][j][k]\),表示枚舉到了\(cnt[i]\),模\(p\)

\(j\),選了\(k\)個形如1111……的數。

那麽狀態轉移方程就很好出來了:

\[f[i+1][(j+l*i)~\texttt{mod}~p][k+l]=(f[i][j][k]*T(l,cnt[i])+f[i+1][(j+l*i)~\texttt{mod}~p][k+l])\]

這裏的\(T(A,B)=C_{A+B-1}^{A}\)根據組合知識很容易求出。

那麽差不多這題也完結了。

我本來以為會爆空間的,畢竟\(f[501][501][11]\)我開的是\(\texttt{long~long}\)。結果洛谷只有\(21\texttt{M}\)多一點點。

要註意三個問題:

  • 開長整型\(\texttt{long long}\)
  • 為了防止前導\(0\)問題,剛開始要填滿111111……
  • 最好弄個滾動數組,滾掉第一維。

代碼有點醜:

#include <bits/stdc++.h>
using namespace std;
typedef int _int;
#define int long long

const int mo=999911659;
int ans;
int n,p,cnt[501],beg,len,pos[501];
int A[10],c[501][11];
int f[501][501][11],a,sum;

_int main()
{
    cin>>n>>p;
    if (n<=p) {
        for (int i=1;i<=n;++i) {
            sum=sum*10+1;
            sum%=p;
            ++cnt[sum];
        }
        a=sum;
    }
    else {
        for (int i=1;i<=p+1;++i) {
            sum=sum*10+1;
            sum%=p;
            if (cnt[sum]) {
                beg=pos[sum];
                len=i-pos[sum];
                break;
            }
            ++cnt[sum];
            pos[sum]=i;
        }
        for (int i=0;i<p;++i)
            if (cnt[i]&&pos[i]>=beg) {
                cnt[i]=(n-beg+1)/len;
                if (pos[i]-beg+1<=(n-beg+1)%len)
                    ++cnt[i];
                if ((pos[i]-beg+1)%len==(n-beg+1)%len)
                    a=i;
            }
    }
    A[1]=1;
    for (int i=2;i<=8;++i)
        A[i]=(mo-mo/i)*A[mo%i]%mo;
    for (int i=0;i<p;++i) {
        c[i][0]=1;
        if (cnt[i])
            for (int j=1;j<=8;++j) {
                c[i][j]=(cnt[i]*c[i][j-1]%mo)*A[j]%mo;
                ++cnt[i];
                cnt[i]%=mo;
            }
    }
    f[0][a][0]=1;
    for (int i=0;i<p;++i) {
        for (int j=0;j<p;++j) {
            for (int k=0;k<9;++k) {
                for (int l=0;l<=k;++l) {
                    f[i+1][j][k]+=f[i][(j-(l*i%p)+p)%p][k-l]*c[i][l]%mo;
                    f[i+1][j][k]%=mo;
                }
            }
        }
    }
    for (int i=0;i<=8;++i)
        ans+=f[p][0][i],ans%=mo;
    cout<<ans;
    return 0;
}

洛谷 P2481 [SDOI2010]代碼拍賣會