2016年省赛H题目改编--H +模逆元

这篇博客详细介绍了如何利用模逆元解决一道改编自2016年省赛H题目的问题。通过列举并转化规律,揭示了在等比数列求和中模逆元的重要性。博主讲解了计算过程,强调在取模运算后需求得9的模逆元以确保正确答案,并展示了代码实现中如何维护10的指数前缀来加速计算。

Swap

Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 13 Solved: 2

Description

Bobo has a n digits decimal number D=d 1 d 2…d n (It may have leading zeros).
Let R(i,j) denotes number D with digits swap the i-th position and j-th position. That is, R(i,j)=d 1…d i-1 d j d i+1…d i d j+1 d j+2…d n.
Bobo would like to find

modulo (10 9+7).

Input

The input contains at most 30 sets. For each set:
The first line contains an integer n (1≤n≤10 5).
The second line contains n digits d 1 d 2…d n (0≤d i≤9).

Output

For each set, an integer denotes the result.

Sample Input

2
12
3
012
10
0123456789

Sample Output

45
369
555555115


Solution :

列举找规律+乘法逆元。举个列子吧。 12345 ,我们按照公式展开。得到

1 2 3 4 5

2 1 3 4 5

3 2 1 4 5

4 2 3 1 5

5 2 3 4 1


1 2 3 4 5 

1 3 2 4 5

1 4 3 2 5

1 5 3 4 2


1 2 3 4 5

1 2 4 3 5

1 2 5 4 3


1 2 3 4 5

1 2 3 5 4


1 2 3 4 5

转化一下就可以得到

得到n行

1 1 1 1 1

2 2 2 2 2

3 3 3 3 3

4 4 4 4 4

5 5 5 5 5

得到n*(n-1)/ 2行

1 2 3 4 5

。。。。

1 2 3 4 5

前面n行,每一行都提取一个 a(a就是当前行的数字),剩下一个等比数列

后面的行,单独计算每一行然后乘以n*(n-1)/ 2


注意:

等比数列求和得到的公式里面是(10^n-1)/ 9,先算上面,然后算下面,上面一定会先进行取模,那么下面就一定要求得9的模逆元才会使得最终答案是正确答案

即:9的逆元为num,那么最终答案是((10^n-1)%mod * num) %mod



然后我的代码里面维护了一个10的指数的前缀

void init()
{
    p[0]=1;
    for(int i=1;i<=MAXN;i++)
        p[i]=p[i-1]*10%mod;
}
求两个互质元素的模逆元

LL qpowMod(LL m,LL n,LL p)
{
    LL ans=1;
    LL temp=m;
    while(n>0)
    {
        if(n&1)
            ans=ans*temp%p;
        temp=temp*temp%p;
        n>>=1;
    }
    return ans;
}
LL getInverse(LL a,LL p)
{
    return qpowMod(a,p-2,p);
}
当a,m不是互质数,计算(b/a)mod m,没办法把b/a转换成b×(a的逆元),可以用  (b/a)mod m == [ b mod (a*m) ] / a 来代替


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

#define LL long long
#define MAXN 100005
const LL mod=1000000000+7;
char str[MAXN];
LL a[MAXN];
LL p[MAXN];

void init()
{
    p[0]=1;
    for(int i=1;i<=MAXN;i++)
        p[i]=p[i-1]*10%mod;
}

LL qpowMod(LL m,LL n,LL p)
{
    LL ans=1;
    LL temp=m;
    while(n>0)
    {
        if(n&1)
            ans=ans*temp%p;
        temp=temp*temp%p;
        n>>=1;
    }
    return ans;
}
LL getInverse(LL a,LL p)
{
    return qpowMod(a,p-2,p);
}

int main()
{
    LL n;
    init();
    LL num=getInverse(9,mod);
    //freopen("in.txt","r",stdin);
    while(scanf("%lld",&n)!=EOF)
    {
        LL sum=0;
        scanf("%s",str);

        LL ans1=0,ans2=1;
        for(int i=0;i<n;i++){
            sum+=str[i]-'0';
            a[i]=str[i]-'0';
            ans1=(ans1*10+a[i])%mod;
        }
        ans1=(ans1*((n*(n-1)/2)%mod))%mod;

        ans2=((p[n]-1)*sum)%mod;
        ans2=(ans2*num)%mod;

        ans1=(ans1+ans2)%mod;
        printf("%lld\n",ans1);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值