hatuoj 1300 HEX----组合数+逆元+思维 山东省第八届省赛D题

本文介绍了一种在六边形网格上计算从起点到任意指定格子的不同路径数量的方法。利用排列组合原理,通过计算向左、向右及垂直移动的步数,采用递推公式并考虑模运算来高效解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题 1300. – HEX

1300: HEX

时间限制: 4 秒   内存限制: 128 MB
提交: 26   解决: 9
提交  状态 
题目描述


On a plain
of hexagonal grid, we define a step as one move from the current grid to the
lower/lower-left/lower-right grid. For example, we can move from (1,1) to
(2,1), (2,2) or (3,2).

In the following graph we give a demonstrate of how this coordinate system works.

Your task is to calculate how many possible ways can you get to grid(A,B) from gird(1,1), where A and B represent the grid is on the B-th position of the A-th line.





输入


For each test case, two integers A
(1<=A<=100000) and B (1<=B<=A) are given in a line, process till
the end of file, the number of test cases is around 1200.

输出
For
each case output one integer in a line, the number of ways to get to the
destination MOD 1000000007.
样例输入

1 1 
3 2
100000 100000
样例输出

1 
3
1
提示

来源

提交  状态 




题意 就是从 1,1开始每次向 ↙ ↓ ↘这几个方向移动,给一个坐标,问到那个点有多少种走法

这肯定是排列组合题目,先把到一个点向左向右走的步数算出来,向左就是 n-m 向右是 m-1 (大佬推出来的规律) ,设 C是竖着走的步数,则走到一个点需要 l+r+c步 ,先把向左向右走看成一个 C(l+r+c,c)(向左向右走的所有情况的个数)这就是 C(l+r+c,c) C(l+r,r)就是所有情况,然后枚举c就可以了
看的大佬的博客都是(l+r+c) ! / ( l! * r! c!) 就是 C(l+r+c,c) C(l+r,r)化简的结果,会减一半时间

注意 除法取余 逆元(需打表,要不会超时)

#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define ll long long
ll re[100009];
ll vi[100009];

ll poww(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=(ans*a)%mod;
        b>>=1;
        a=(a*a)%mod;

    }
    return ans;
}
void intt()
{
    re[0]=1;
    vi[0]=1;

    for(int i=1;i<=100003;i++)
    {
        re[i]=(i*re[i-1])%mod;
        vi[i]=poww(re[i],mod-2)%mod;
        //cout<<vi[i]<<endl;
    }

}
ll  C(int a,int b)
{

    return  (re[a]*(vi[a-b]%mod*vi[b]%mod)%mod)%mod;
}
int main()
{
   // ios::sync_with_stdio(false);
    ll n,m;
    intt();
    while(cin>>n>>m)
    {   ll ans=0;
        //int i=m;
       int l=n-m,r=m-1;
       int c=0;
     //  int k=l+r-1;
       while(l>=0&&0<=r)
       {
           ans+=C(l+r+c,c)*C(l+r,r)%mod;
          // ans+=re[l+r+c]*(vi[l]%mod*vi[r]%mod*vi[c]%mod)%mod;
           ans%=mod;

           c++;
           l--;
           r--;
       }
        cout<<ans<<endl;
    }
    return 0;
}
<think>我们遇到了一个错误:没有找到名为 'Crypto' 的模块。这是因为我们使用了 `Crypto.Util.number` 中的 `bytes_to_long` 和 `long_to_bytes` 函数,但是环境中没有安装 `pycryptodome` 库。 解决方案: 1. 安装 `pycryptodome` 库:在命令行中运行 `pip install pycryptodome` 2. 或者,我们可以自己实现这两个函数,避免依赖外部库。 考虑到问要求简单,我们可以自己实现这两个函数: - `bytes_to_long`: 将字节串转换为大整数(大端序) - `long_to_bytes`: 将大整数转换为字节串(大端序) 下面我们重新编写代码,移除对 `Crypto` 模块的依赖,并自行实现这两个函数。</think>错误信息表明您的环境中缺少 `pycryptodome` 库,这是提供 `Crypto.Util.number` 模块的库。以下是解决方案: ### 解决方案:安装依赖库并实现替代函数 ```python # 安装必要的库 # 在终端或命令提示符中运行: # pip install pycryptodome # 如果无法安装pycryptodome,可以使用以下替代实现 import base64 import math def bytes_to_long(s): """将字节序列转换为大整数(大端序)""" n = 0 for b in s: n = (n << 8) | b return n def long_to_bytes(n, size=None): """将大整数转换为字节序列(大端序)""" # 计算所需字节数 if size is None: size = (n.bit_length() + 7) // 8 return n.to_bytes(size, 'big') def decode_base64(encoded_str): """解码 URL 安全的 Base64 字符串为字节序列""" # 添加必要的填充 padding_needed = 4 - (len(encoded_str) % 4) if padding_needed != 4: encoded_str += '=' * padding_needed # 替换 URL 安全字符 url_safe_str = encoded_str.replace('-', '+').replace('_', '/') # Base64 解码 return base64.b64decode(url_safe_str) def extended_gcd(a, b): """扩展欧几里得算法求逆元""" if b == 0: return (1, 0, a) else: x, y, gcd = extended_gcd(b, a % b) return (y, x - (a // b) * y, gcd) def mod_inverse(a, m): """求模逆元""" x, y, gcd = extended_gcd(a, m) if gcd != 1: return None # 逆元不存在 else: return x % m def rabin_decrypt(c, p, q): """Rabin 解密算法""" n = p * q # 计算 c mod p 和 c mod q mp = pow(c, (p + 1) // 4, p) mq = pow(c, (q + 1) // 4, q) # 使用扩展欧几里得算法求 yp 和 yq yp = mod_inverse(p, q) yq = mod_inverse(q, p) # 组合四个可能的解 r1 = (yp * p * mq + yq * q * mp) % n r2 = n - r1 r3 = (yp * p * mq - yq * q * mp) % n r4 = n - r3 return [r1, r2, r3, r4] # 主程序 if __name__ == "__main__": encoded_data = "8zExgBEudX5CZqcAh2k5nGFUxsQ75EtoD2boeb5ap6yKCtTQxWSiXqhaiAJQzZmXxa7" try: # 1. 解码 Base64 decoded_bytes = decode_base64(encoded_data) print(f"解码后的字节: {decoded_bytes}") print(f"十六进制表示: {decoded_bytes.hex()}") # 2. 转换为整数(Rabin 密文) cipher_int = bytes_to_long(decoded_bytes) print(f"密文整数: {cipher_int}") # 3. Rabin 解密(需要私钥 p 和 q) # 实际应用中应从安全位置获取私钥 # 这里是示例值,需要替换为实际密钥 p = 104999 # 示例质数 q = 115249 # 示例质数 possible_plaintexts = rabin_decrypt(cipher_int, p, q) # 4. 尝试将每个可能的解转换为字节序列 print("\n可能的解密结果:") for i, pt in enumerate(possible_plaintexts): try: # 尝试转换为字节序列 result_bytes = long_to_bytes(pt) # 尝试 UTF-8 解码 result_str = result_bytes.decode('utf-8') print(f"选项 {i+1} (文本): {result_str}") except UnicodeDecodeError: # 如果无法解码为文本,显示十六进制 print(f"选项 {i+1} (二进制): {result_bytes.hex()}") except Exception as e: print(f"处理过程中发生错误: {str(e)}") ``` ### 代码解释 1. **解决依赖问**: - 提供了两种解决方案: * 安装 `pycryptodome` 库(推荐):运行 `pip install pycryptodome` * 使用自定义实现的 `bytes_to_long` 和 `long_to_bytes` 函数 2. **自定义转换函数**: - `bytes_to_long`:将字节序列转换为大整数(大端序) - `long_to_bytes`:将大整数转换回字节序列(大端序) 3. **Rabin 解密流程**: - 首先解码 Base64 字符串得到密文字节序列 - 将字节序列转换为整数作为 Rabin 密文 - 使用 Rabin 解密算法(需要私钥 p 和 q)得到四个可能的明文 - 尝试将每个可能的明文转换为可读文本 ### 运行说明 1. **推荐方法(安装依赖)**: ```bash pip install pycryptodome python task.py ``` 2. **替代方法(使用自定义函数)**: 直接运行上述代码,不需要安装额外依赖 ### 注意事项 - 示例中的 `p` 和 `q` 是随意选择的质数,实际应用中需要替换为正确的私钥 - Rabin 解密会产生四个可能结果,需要通过消息格式或上下文判断正确的结果 - 如果解密结果不是可读文本,可能需要进一步处理(如检查是否包含其他加密层)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值