codeforces 327C. Magic Five

C. Magic Five
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

There is a long plate s containing n digits. Iahub wants to delete some digits (possibly none, but he is not allowed to delete all the digits) to form his "magic number" on the plate, a number that is divisible by 5. Note that, the resulting number may contain leading zeros.

Now Iahub wants to count the number of ways he can obtain magic number, modulo 1000000007 (109 + 7). Two ways are different, if the set of deleted positions in s differs.

Look at the input part of the statement, s is given in a special form.

Input

In the first line you're given a string a (1 ≤ |a| ≤ 105), containing digits only. In the second line you're given an integer k (1 ≤ k ≤ 109). The plate s is formed by concatenating k copies of a together. That is n = |ak.

Output

Print a single integer — the required number of ways modulo 1000000007 (109 + 7).

Sample test(s)
input
1256
1
output
4
input
13990
2
output
528
input
555
2
output
63
Note

In the first case, there are four possible ways to make a number that is divisible by 5: 5, 15, 25 and 125.

In the second case, remember to concatenate the copies of a. The actual plate is 1399013990.

In the third case, except deleting all digits, any choice will do. Therefore there are 26 - 1 = 63 possible ways to delete digits.

题意:给你n个同样的字符串,你在里面任意删除数字,使剩下的数字刚好能被5整除(数字前缀可以为0)。

思路:一个数要被5整除,那么它的末尾只能是5或0。如13090,它的长度len=5,假设有n个这个样的串;

那么先分析体格串的删法:

如果以中间的0为末尾,那么后面的都是要删去的,但是中间那个0前面的1和3可删可不删,此时有2^2种;

如果以后面的的0为末尾,那么前面的四个数都可删可不删,此时总共有2^4种;

那么一个这样的串总的删法有2^2+2^4种。

现在再看130901309013090,它的长度Len=5*3:

它总共有2^2+2^4+2^7+2^9+2^12+2^14=(2^2+2^4) + 2^5*(2^2+2^4) + (2^5)^2*(2^2+2^4).

那么现在看出它是有规律的,等比数列求和,我们发现以一串字符的结果为首项,以2^len为公比的n项等比数列求和。

a1*(2^(len*n)-1) / (2^len-1)就是我们所求的答案;那么现在问题又来了,题目的数据特别大,不能这样直接算,我们采取快速幂,当然要对1e9+7取模,我们再次用到费马小定理(a^(-1)%P=a^(P-2)%P,这样处理一下分母,转化为乘法逆元,然后直接乘起来就好。

AC代码:

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>

using namespace std;

typedef long long LL;
const int INF=0x3f3f3f3f;
const double eps=1e-10;
const double PI=acos(-1.0);

const int maxn=100009;
const int mod=1e9+7;

char s[maxn];
LL a[maxn];
LL n;

LL quickpow(LL n,LL m)
{
    LL tmp=1;
    while(m>0)
    {
        if(m&1)
            tmp=(tmp*n)%mod;
        n=(n*n)%mod;
        m>>=1;
    }
    return tmp;
}

LL Fm(LL x)//费马小定理
{
    return quickpow(x,mod-2)%mod;
}

int main()
{
    while(~scanf("%s%lld",s,&n))
    {
        int cnt=0;
        LL ans=0;
        LL len=strlen(s);

        for(int i=0;i<len;i++)
        {
            if(s[i]=='0'||s[i]=='5')
                ans=(ans+quickpow(2,i))%mod;
        }

        LL q=(Fm(quickpow(2,len)-1))%mod;
        LL tmp=(quickpow(2,len*n)-1)%mod;
        ans=(ans*tmp%mod)*q%mod;//这里一定要边乘边取模,后面数据会特别大
        printf("%lld\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值