F - Nim

F - Nim

Problem Statement

You are given integers N,A1,A2,A3. Find the number, modulo 998244353, of triples of positive integers (X1,X2,X3) that satisfy all of the following three conditions.

  • 1XiN for every i.
  • Xi is a multiple of Ai for every i.
  • (X1X2)X3=0, where denotes bitwise xor.
What is bitwise xor? The bitwise xor of non-negative integers A and B, AB, is defined as follows.
  • When AB is written in binary, the 2ks place (k0) is 1 if exactly one of the 2ks places of A and B is 1, and 0 otherwise.
For instance, 35=6 (in binary: 011101=110).

Constraints

  • 1N1018
  • 1Ai10
  • All input values are integers.

Input

The Input is given from Standard Input in the following format:

N A1 A2 A3

Output

Print the answer.  


Sample Input 1

13 2 3 5

Sample Output 1

4

Four triples (X1,X2,X3) satisfy the conditions: (6,3,5),(6,12,10),(12,6,10),(12,9,5).


Sample Input 2

1000000000000000000 1 1 1

Sample Output 2

426724011

Sample Input 3

31415926535897932 3 8 4

Sample Output 3

759934997

 

解题思路

  用刚学的递归写法来做这道数位 dp,请参考数位 dp 学习笔记(灵神模板)

  对 X1X2X3 同时进行数位 dp,找的是满足条件的三元组的数量。很显然由于涉及到异或运算,需要把 Xi 看作是二进制数。考虑参数的选择,由于要满足 AiXi 因此还需要用一个参数 ri 来记录前 u 位所表示的二进制数模 Ai 的值。另外由于询问的区间是 [1,N],所以不可以有前导零。最后在枚举 X1X2X3u 位选择的数 x1x2x3 时,要保证 x1x2x3=0

  一些技巧,事实上并不需要把 Xi 转换成二进制字符串然后 dp,直接用 Xi >> u & 1 来得到 Xi 在二进制下第 u 位的值。由于 N 最大为 1018,因此二进制位最多有 60 位,所以一开始传入的参数 uu=59,从高位往低位递归,边界条件是 u=1

  AC 代码如下,时间复杂度为 O(logNA3)

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 60, mod = 998244353;

LL n, a1, a2, a3;
int f[N][10][10][10][2][2][2][2][2][2];

int dfs(int u, int r1, int r2, int r3, int h1, int h2, int h3, int l1, int l2, int l3) {
    if (u < 0) return !r1 && !r2 && !r3 && !l1 && !l2 && !l3;
    if (f[u][r1][r2][r3][h1][h2][h3][l1][l2][l3] != -1) return f[u][r1][r2][r3][h1][h2][h3][l1][l2][l3];
    int ret = 0;
    int up1 = h1 ? n >> u & 1 : 1, up2 = h2 ? n >> u & 1 : 1, up3 = h3 ? n >> u & 1 : 1;
    for (int x1 = 0; x1 <= up1; x1++) {
        for (int x2 = 0; x2 <= up2; x2++) {
            for (int x3 = 0; x3 <= up3; x3++) {
                if (!(x1 ^ x2 ^ x3)) ret = (ret + dfs(u - 1, (r1 * 2 + x1) % a1, (r2 * 2 + x2) % a2, (r3 * 2 + x3) % a3, h1 && x1 == up1, h2 && x2 == up2, h3 && x3 == up3, l1 && !x1, l2 && !x2, l3 && !x3)) % mod;
            }
        }
    }
    return f[u][r1][r2][r3][h1][h2][h3][l1][l2][l3] = ret;
}

int main() {
    scanf("%lld %lld %lld %lld", &n, &a1, &a2, &a3);
    memset(f, -1, sizeof(f));
    printf("%d", dfs(59, 0, 0, 0, 1, 1, 1, 1, 1, 1));
    
    return 0;
}

 

参考资料

  Editorial - GAMEFREAK Programming Contest 2023 (AtCoder Beginner Contest 317):https://atcoder.jp/contests/abc317/editorial/7047

posted @   onlyblues  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2023-01-27 B. GCD Partition
2023-01-27 D. Fixed Prefix Permutations
Web Analytics
点击右上角即可分享
微信分享提示