您的位置:首页 > 其它

hdu 3652 B-number(数位dp)

2014-11-02 02:09 423 查看
相当于对 求[1, n]中包含13的数字 这个问题多加了一个限制,要求被13整除。

于是改写原来的状态 f(k, i, j, l) 前面两维依旧,以i开头位数为k。j取1 or 0,表示是否包含13,l 取 [0, 13) 表示MOD13后余数为l。

在计数的时候,还要维护一个变量,用来表示前面的数位是否包含13,因为这里不像只需要判断是否包含13的情况,现在不能直接break。

同时可以维护一个mod, 表示前面的高位与n相同,后面取0的数MOD13的结果。这样枚举l的时候,便可以直接 (mod+l)%13 得到整个数MOD13的值。

int f[11][11][13][2], d[11], b[11], n;
int solve() {
    int len = 0;
    while (n) {
        d[len++] = n%10;n /= 10;
    }
    d[len] = 0;
    b[1] = 1;
    for (int i=2;i<=len;++i) b[i] = b[i-1]*10%13;
    int m = 0, flag = 0, ans = 0;
    for (int i=len-1;i>=0;--i) {
        for (int j=0;j<d[i];++j) {
            int tmp = (13 - m)%13;
            ans += f[i+1][j][tmp][1];
            if (flag || d[i+1] == 1 && j == 3) {
                ans += f[i+1][j][tmp][0];
            }
        }
        if (d[i+1] == 1 && d[i] == 3) flag = 1;
        m = (m+d[i]*b[i+1])%13;
    }
    return ans;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("input.in", "r", stdin);
#endif
    //SPEED_UP
    while (cin >> n) {
        memset(f, 0, sizeof(f));
        f[0][0][0][0] = 1;
        int base = 1;
        for (int i=1;i<=10;++i) {
            for (int j=0;j<10;++j)
                for (int k=0;k<10;++k)
                    for (int l=0;l<13;++l) {
                        int tmp = (l+j*base)%13;
                        if (j == 1 && k == 3) {
                            f[i][j][tmp][1] += f[i-1][k][l][0] + f[i-1][k][l][1];
                        }
                        else {
                            f[i][j][tmp][0] += f[i-1][k][l][0];
                            f[i][j][tmp][1] += f[i-1][k][l][1];
                        }
                    }
            base *= 10;base %= 13;
        }
        n += 1;
        cout << solve() << endl;
    }

    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: