【洛谷题解】P9006神树大人挥动法杖(Hard Version)

题面分析(题目写了啥)

题目要求将从 1 0 n − 1 10^{n−1} 10n1 1 0 n − 1 10^n−1 10n1 的所有 n n n 位数按照 m o d   k mod\ k mod k 的结果分成 k k k 组,并计算每一组的个数。由于直接枚举肯定不行(因为 n n n 可以达到 5000 5000 5000),我们需要用差分思想+数学解决这个问题。

难点解析(写到一半不会了)

  • k k k 的分布规律

1 0 n − 1 10^{n−1} 10n1 1 0 n − 1 10^n−1 10n1 的所有 n n n 位数,这些数在模 k k k 下的分布是有循环性的,因此可以用差分算法。

  • 计算每个 m o d   k mod\ k mod k 的余数的个数

总数:从 1 0 n − 1 10^{n−1} 10n1 1 0 n − 1 10^n−1 10n1 的数的总数是 1 0 n − 1 0 n − 1 10^n−10^{n−1} 10n10n1

m o d   k mod\ k mod k 的分布:这些数在 m o d   k mod\ k mod k 下的分布是均匀的,但仍会出现边界问题,处理方法也很简单,如下:

  • 边界处理

最小值: 1 0 n − 1   m o d   k 10^{n−1}\ mod\ k 10n1 mod k

最大值: 1 0 n − 1   m o d   k 10^n−1\ mod\ k 10n1 mod k

代码结构(可对照下文使用)

  • fp函数

快速幂模板结构,快速幂详细了解请查阅这里,这里不做过多解释。

  • zong变量

计算 1 0 n − 1   m o d   k 10^{n−1}\ mod\ k 10n1 mod k ,确定边界。

  • sheng变量

计算符合题意的量,即每个 m o d   k mod\ k mod k 的余数的个数。

  • ans数组

遍历每个 m o d   k mod\ k mod k 的余数,根据边界情况调整每个组的个数。结果对 100000007 100000007 100000007 取模后输出即可。

激动人心的代码时刻!

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M = 100000007; //模

int ans[1000005]; //答案数组

// 快速幂函数模板
int fp(int a,int b,int mod){
    a %= mod;
    int ans = 1;
    while(b){
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}

signed main(){
    ios::sync_with_stdio(0);
    int n, k;
    cin >> n >> k;

    // 计算 10^(n-1) 的相关值
    int zong = (fp(10,n - 1,k) - 1 + k) % k; // 10^(n-1) % k
    int sheng = (fp(10,n - 1,M) - 1 - zong + M) * fp(k,M - 2,M) % M;
    
    // 初始化答案数组
    for(int i = 0; i < k; i++){
        ans[i] -= sheng;
        if (i != 0 && i <= zong) ans[i]--;
    }
    
    // 计算 10^n 的相关值
    zong = (fp(10,n,k) - 1 + k) % k; // 10^n % k
    sheng = (fp(10,n,M) - 1 - zong + M) * fp(k,M - 2,M) % M;
    
    // 更新答案数组输出
    for(int i = 0;i < k;i++){
        ans[i] += sheng;
        if (i != 0 && i <= zong) ans[i]++;
        ans[i] = (ans[i] + M) % M; // 确保结果为正
        cout << ans[i] << " ";
    }
    return 0; //金星:完美V

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值