【GDOI2018Day1模拟4.17】凫趋雀跃

Description:

这里写图片描述
【GDOI2018Day1模拟4.17】凫趋雀跃_第1张图片

题解:

把(0,0)也视为一个 ki

显然要容斥原理。

枚举一个s,去求至少有s步是不合法的方案数。

这个要dp三个东西。

fi,j 表示走了i步, k =j*10的方案数。

横纵坐标没有关联,可以分开dp。

pi,j 表示走了i步,横坐标之和为j的方案数。

qi,j 表示走了i步,纵坐标之和为j的方案数。

那么 Ans=i,j(1)i(ri)fi,jpri,txj10qri,tyj10

这个为什么是对的呢。

考虑一种确切的走法,它有t步是不合法的。

在上面那个式子中,它会被计算 ti=0(1)i(ti)=[t=0]

所以上面那个式子刚好只会计算没有出现过不合法的方案数。

这个好像是先有结论再有证明,但是似乎也只能是这样了。

#include
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;

const int mo = 1e4 + 7;

int tx, ty, mx, my, r, K, k[55], ans, bz[81];
int f[1605][81], p[1605][801], q[1605][801], s[801], c[1601][1601];

int main() {
    freopen("jump.in", "r", stdin);
    freopen("jump.out", "w", stdout);
    scanf("%d %d %d %d %d %d", &tx, &ty, &mx, &my, &r, &K);
    fo(i, 1, K) scanf("%d", &k[i]), bz[k[i] / 10] = 1;
    mx = min(mx, tx); my = min(my, ty); bz[0] = 1;
    f[0][0] = 1;
    fo(i, 1, r) fo(j, 0, min(tx, ty) / 10) fo(u, 0, j)
        if(bz[j - u]) f[i][j] = (f[i - 1][u] + f[i][j]) % mo;
    fo(j, 0, tx) s[j] = 1;
    fo(i, 1, r) {
        fo(j, 0, tx) p[i][j] = (s[j] - ((j - mx - 1 < 0) ? 0 : s[j - mx - 1]) + mo) % mo;
        s[0] = p[i][0];
        fo(j, 1, tx) s[j] = (p[i][j] + s[j - 1]) % mo;
    }
    fo(j, 0, ty) s[j] = 1;
    fo(i, 1, r) {
        fo(j, 0, ty) q[i][j] = (s[j] - ((j - my - 1 < 0) ? 0 : s[j - my - 1]) + mo) % mo;
        s[0] = q[i][0];
        fo(j, 1, ty) s[j] = (q[i][j] + s[j - 1]) % mo;
    }
    c[0][0] = 1;
    fo(i, 1, r) {
        c[i][0] = 1;
        fo(j, 1, i) c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mo;
    }
    fo(i, 0, r) fo(j, 0, min(tx, ty) / 10)
        ans += ((i % 2) ? -1 : 1) * f[i][j] % mo * p[r - i][tx - j * 10] % mo * q[r - i][ty - j * 10] % mo * c[r][i] % mo;
    printf("%d", (ans % mo + mo) % mo);
}

你可能感兴趣的:(动态规划,数论杂集)