码迷,mamicode.com
首页 > 其他好文 > 详细

AT2582 [ARC075D] Mirrored

时间:2020-11-19 13:04:09      阅读:30      评论:0      收藏:0      [点我收藏+]

标签:简单的   size   get   这一   pac   const   方案   实现   思路   

首先因为这个问题的解的范围我们是不清楚的,可以先考虑一下解的范围以便后面的解题。

那么我们可以大胆猜测这个数的位数应该不会很长,否则除非使用一条与 \(D\) 有关的式子外,不论我们用什么方法都计算不出来了。

进一步观察可以发现,这个数的位数不会超过 \(D\) 的位数的两倍,证明如下(利用反证法):

\(N\) 加上 \(D\) 之后不会进位到前 \(|\frac{N}{2}|\) 个位置,那么显然此时 \(N\) 会构成回文串,因为 \(D > 1\) 这是不可能的。

否则,\(|\frac{N}{2}| \sim |D| + 1\) 位必然全为 \(9\),则 \(|\frac{N}{2}| + D \sim |\frac{N}{2}| + 1\) 为必然全为 \(0\),此时不会满足互为反串的要求。

那么一个最简单的思路就浮现出来了,可以考虑枚举 \(N\) 的位数然后计算在这个位数下有多少个数可以满足条件。

注意到我们只需确定后 \(|\frac{n}{2}|\) 个位置即可确定 \(N\),于是可以考虑暴力 \(dfs\) 枚举每个位置填什么然后配合一些剪枝就可以通过本题了。

但是否存在复杂度更优秀的做法呢?是存在的。

同样只考虑最后 \(|\frac{n}{2}|\) 位填什么。

可以发现暴力 \(dfs\) 是不需要的,因为之前位置对当前位置的影响仅在于是否会对当前位置产生进位。

可以考虑使用 \(dp\) 解决这个问题,根据上面的理论可以考虑令 \(f_{i, 0 / 1}\) 表示当前填到第 \(i\) 位之前对这一位是否产生进位的方案数。

但是最终我们无法通过这个状态来确定前 \(|\frac{n}{2}|\) 个数是否合法,同时因为 \(dp\) 状态没办法具体描述每个位置填了什么,因此在 \(dp\) 之后判断是否合法是不可行的。

那么就必须保证在 \(dp\) 的过程中保证每一位都必须合法。

可以发现对于第 \(p\) 位假设填为 \(i\),那么 \(n - p + 1\) 位必然填 \(j = i + D_i + lx\) 其中 \(lx\) 表示是否之前存在进位。

这一位合法的条件当且仅当 \((j + D_{n - p + 1} + rx) \% 10 = i\) (其中 \(rx\) 表示之后是否会进位到 \(n - p + 1\)),且满足之前一位是否需要进位的需求。

于是此时判定的方法就呼之欲出了,只需要在 \(dp\) 的时候多记一维令 \(f_{i, 0 / 1, 0 / 1}\) 表示当前考虑到第 \(i\) 位之前是否会对第 \(i\) 位产生进位,第 \(n - i + 1\) 位是否需要之后产生进位。

转移的时候只需要考虑这一位填什么然后把不合法的情况判掉即可,使用记忆化搜索实现。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; ++i)
const int N = 20 + 5;
int n, d, ans, a[N], dp[N][2][2];
int read() {
    char c; int x = 0, f = 1;
    c = getchar();
    while (c > ‘9‘ || c < ‘0‘) { if(c == ‘-‘) f = -1; c = getchar();}
    while (c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘, c = getchar();
    return x * f;
}
int calc(int x) { int ans = 0; for (; x; x /= 10, ++ans) a[ans + 1] = x % 10; return ans;}
int dfs(int p, int lx, int rx, int L) {
    if(p > (L + 1) / 2) return !(lx ^ rx);
    if(dp[p][lx][rx] != -1) return dp[p][lx][rx];
    int ans = 0;
    rep(i, 0, 9) {
        int j = (i + lx + a[p]) % 10; 
        if(p == 1 && !j) continue ;
        if((L & 1) && (p == (L + 1) / 2)) {
            if(i != j) continue;
            ans += dfs(p + 1, i + lx + a[p] > 9, rx, L);
        }
        else {
            if(!rx && j + a[L - p + 1] > 9) continue ;
            if(rx && j + a[L - p + 1] < 9) continue ;
            if(rx && j + a[L - p + 1] == 9 && i) continue ;
            if((j + a[L - p + 1]) % 10 != i && (j + a[L - p + 1] + 1) % 10 != i) continue ;
            if(!rx && j + a[L - p + 1] + 1 > 9 && (j + a[L - p + 1]) % 10 != i) continue ;
            ans += dfs(p + 1, i + lx + a[p] > 9, (j + a[L - p + 1]) % 10 != i, L);
        }
    }
    return dp[p][lx][rx] = ans;
}
signed main() {
    d = read(), n = calc(d);
    rep(i, n, 2 * n) memset(dp, -1, sizeof(dp)), ans += dfs(1, 0, 0, i);
    printf("%lld", ans);
    return 0;
}

AT2582 [ARC075D] Mirrored

标签:简单的   size   get   这一   pac   const   方案   实现   思路   

原文地址:https://www.cnblogs.com/Go7338395/p/13975665.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!