NOI 模拟赛

T1 手机号码

求有多少 $L,R$ 之间的 $11$ 位数同时满足

1. $4$ 和 $8$ 不同时出现

2.有三连相同数字

$L,R$ 都是 11 位数

sol:

数位 dp

记状态为 第 $i$ 位,前一位是 $pre$ ,前一位和前前一位是否相同,是否有 $4$ ,是否有 $8$ ,是否计入答案

然后搜索就完事了

考场上三个大锅

1.$L,R$ 虽然都是 $11$ 位数,但 $L-1$ 不一定是 $11$ 位数

2.竟然访问了数组的 $-1$ 。。。(“没有前一位”的状态我标的是 $-1$,其实用 $10$ 就可以了)

3.不管搜索的时候有没有 $lim$,直接就把 dp 清零了,竟然没出锅...

#include <bits/stdc++.h>
#define int long long
#define LL long long
#define rep(i, s, t) for (register LL i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for (register LL i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline int read() {
    int x = 0, f = 1; char ch;
    for (ch = getchar(); !isdigit(ch); ch = getchar()) if (ch == '-') f = -f;
    for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
    return x * f;
}
int dig[30];
LL dp[50][12][2][2][2][2];
LL dfs(LL pos, LL pre, LL ispre, LL if4, LL if8, LL lim, LL mz) {
    if(pos == 0) return mz;
    if(!lim && (~dp[pos][pre][ispre][if4][if8][mz])) return dp[pos][pre][ispre][if4][if8][mz];
    dp[pos][pre][ispre][if4][if8][mz] = 0;
    LL res = 0, Bound = lim ? dig[pos] : 9;
    rep(i, 0, Bound) {
        if(((i == 0) && (pos == 11)) || (if4 && (i == 8)) || (if8 && (i == 4))) continue;
        res += dfs(pos - 1, i, (i == pre), if4 || (i == 4), if8 || (i == 8), lim && (i == Bound), mz || ((i == pre) && ispre));
    }
    if(!lim) dp[pos][pre][ispre][if4][if8][mz] = res;
    return res;
}
LL L, R;
LL solve(LL x) {
    int num = 0;
    memset(dp, -1, sizeof(dp));
    memset(dig, 0, sizeof(dig));
    while(x) {
        dig[++num] = x % 10;
        x = x / 10;
    }
    return dfs(11, -1, 0, 0, 0, 1, 0);
}
signed main() {
    cin >> L >> R; //LL x =  solve(L - 1), y = solve(R);
    cout << solve(R) - solve(L - 1) << endl;
}
View Code

 

T2 补退选

不写了,弱智题,空间开小了 10 倍都能过

 

T3 猪国杀

posted @ 2019-03-19 10:41  探险家Mr.H  阅读(199)  评论(0编辑  收藏  举报