「Codeforces 70C」Lucky Tickets

题目链接:Codeforces 70C

在海象国,一张车票由 $2$ 个数字组成 $(a,b)$,表示第 $a$ 系列车票的第 $b$ 张。定义一张车票是幸运的当且仅当 $a\times b=\text{rev}(a)\times\text{rev}(b)$,其中 $\text{rev}(x)$ 函数是将 $x$ 在十进制下翻转的结果(去掉前导零)。

交通管理委员会想新发布 $x$ 个系列的车票,每个系列包含 $y$ 张车票,要求这里面至少有 $w$ 张幸运的车票,并且车票总数 $x\times y$ 要尽量少。系列号由 $1$ 到 $x$ 标号,车票号由 $1$ 到 $y$ 标号。委员会要求不能发布超过 $\max_x$ 个系列,每个系列不能超过 $\max_y$ 张车票。无解输出 $-1$。

数据范围:$1\le \max_x,\max_y\le 10^5$,$1\le w\le 10^7$。


Solution

我们考虑把 $(i,\text{rev}(i))$ 存进一个 $\text{map}​$,表示这样的组合有多少个。

首先判断无解情况,我们把 $1$ 到 $\max_x$ 都加入,然后求出满足条件的最小 $y$。如果在 $1$ 到 $\max_y$ 范围内没有满足条件的 $y$ 则无解。

此时我们贪心确定了 $x(\max_x)$ 和 $y$ 的值。尝试缩小 $x$ 的值,减去贡献;如果此时幸运车票数量少于 $w$ 那么增大 $y​$ 的值直到满足条件位置(显然解有单调性),在此过程中不断更新答案即可。

时间复杂度:$\mathcal O(\max_x\log \max_x)$。


Code

#include <cstdio>
#include <algorithm>
#include <map>

const int N = 1e5 + 5;

int mx, my, w, r[N];
std::map<std::pair<int, int>, int> mpx, mpy;

int rev(int x) {
    int s[10], len=0;
    for (; x; s[++len] = x % 10, x /= 10);
    int ans = 0;
    for (int i = 1; i <= len; i++) {
        ans = 10 * ans + s[i];
    }
    return ans;
}
std::pair<int, int> calc(int x, bool flg) {
    int y = r[x], g = std::__gcd(x, y);
    if (flg) std::swap(x, y);
    return std::make_pair(x / g, y / g);
}
int init(int &ans) {
    for (int i = 1; i <= my; i++) {
        std::pair<int, int> t = calc(i, 1);
        ans += mpx[t], mpy[t]++;
        if (ans >= w) return i;
    }
    return 0;
}
int main() {
    scanf("%d%d%d", &mx, &my, &w);
    for (int i = 1; i <= 100000; i++) {
        r[i] = rev(i);
    }
    for (int i = 1; i <= mx; i++) {
        mpx[calc(i, 0)]++;
    }
    int sum = 0, y = init(sum), x = mx;
    if (sum < w) {
        puts("-1");
        return 0;
    }
    int ans = x * y, ansx = x, ansy = y;
    while (x) {
        mpx[calc(x, 0)]--;
        sum -= mpy[calc(x, 0)];
        x--;
        while (y < my && sum < w) {
            y++;
            mpy[calc(y, 1)]++;
            sum += mpx[calc(y, 1)];
        }
        if (x <= mx && y <= my && sum >= w && x * y < ans) {
            ans = x * y, ansx = x, ansy = y;
        }
    }
    printf("%d %d\n", ansx, ansy);
    return 0;
}

发表评论