• [SDOI2010]代码拍卖会——DP


    原题戳这里
    绝对是一道好题
    需要注意到两个东西
    **
    1.符合条件的数可以拆成一堆(11...11)相加的形式,比如(1145=1111+11+11+11+1)
    2.(1,11,111,1111,...)(p)会出现循环,循环节长度不超过(p)
    **
    还有就是(11...11)最多为(9)个,然后就可以(dp)
    首先需要统计长度为(1-n)的全(1)串中有多少个模(p)(r),记为(cnt[r]),这个可以(O(p))的预处理出来
    接着设(f[k][i][j])表示在(cnt[1]-cnt[i])中已经选了(k)个,且它们的和模(p)(j)的方案数,那么转移如下:

    [f[k+l][i][(j+l imes i)\% p]+=inom{cnt[i]+l-1}{l}f[k][i-1][j],0leqslant k+lleqslant 8 ]

    为什么是(8)而不是(9)呢?因为我们至少要选一个长度为(n)的全(1)串,为了方便,我们在(dp)之前就把它选出来,相当于占用了(9)个中的(1)
    还有就是那个组合是可重组合
    细节看代码吧:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define $SHOW(x) cout << #x" = " << x << endl
    
    #define ll long long
    #define MOD 999911659
    #define MAXN 500
    
    ll n, P, all, cnt[MAXN + 5], inv[10]; // all代表长度为n的全1串模p的值
    int st, len, pos[MAXN + 5], f[10][MAXN + 5][MAXN + 5];
    
    void add(int &x, int y) {
        x = (x + y) % MOD;
        if(x < 0) x += MOD;
    }
    
    int Mul(int x, int y) {
        return 1LL * x * y % MOD;
    }
    
    int fpow(int x, int p) {
        int ret = 1;
        while (p) {
            if (p & 1) ret = Mul(ret, x);
            x = Mul(x, x);
            p >>= 1;
        }
        return ret;
    }
    
    int C(ll n, ll m) {
        if (n < m) return 0;
        int ret = 1;
        for (ll x = n, y = 1; y <= m; --x, ++y)
            ret = Mul(ret, Mul(x % MOD, inv[y]));
        return ret;
    }
    
    int main() {
        cin >> n >> P;
        if (n <= P) { // 预处理循环节
            int sum = 0;
            for (int i = 1; i <= n; ++i) {
                sum = (sum * 10 + 1) % P;
                cnt[sum]++;
            }
            all = sum;
        }
        else {
            int sum = 0;
            for (int i = 1; i <= P + 1; ++i) {
                sum = (sum * 10 + 1) % P;
                if (cnt[sum]) {
                    st = pos[sum], len = i - pos[sum];
                    break;
                }
                pos[sum] = i, cnt[sum]++;
            }
            for (int i = 0; i < P; ++i)
                if (cnt[i] && pos[i] >= st) {
                    cnt[i] = (n - st + 1) / len;
                    if (pos[i] - st + 1 <= (n - st + 1) % len) cnt[i]++;
                    if ((pos[i] - st + 1) % len == (n - st + 1) % len) all = i;
                }
        }
        for (int i = 1; i <= 8; ++i) inv[i] = fpow(i, MOD - 2);
        f[0][0][all] = 1; // 初始化
        for (int r = 0; r < P; ++r) {
            for (int i = 0; i <= 8; ++i)
                for (int k = 0; k < P; ++k)
                    for (int j = 0; j + i <= 8; ++j)
                        if(cnt[r]) add(f[i + j][r + 1][(k + j * r % P) % P], Mul(C(cnt[r] + j - 1, j), f[i][r][k]));
                        else f[i][r + 1][k] = f[i][r][k]; // 注意这里,要把值继承过来
        }
        int ans = 0;
        for (int i = 0; i <= 8; ++i)
            add(ans, f[i][P][0]);
        printf("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    Android下拉刷新-SwipeRefreshLayout,RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout)
    自定义EditText实现一键删除数据
    Androidstudio 点9图报错的问题
    安卓Design包之CoordinatorLayout配合AppBarLayout,ToolBar,TabLaout的使用
    深入了解Hibernate的缓存使用
    跟大牛之间关于hibernate的一些探讨记录
    oracle第一招之神马都是浮云
    大鹏教你如何开发购物网站(里面都是满满的爱)
    JSTL&EL(程序员必看之一)
    动态网页开发
  • 原文地址:https://www.cnblogs.com/dummyummy/p/11061284.html
Copyright © 2020-2023  润新知