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.
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 = |a|·k.
Print a single integer — the required number of ways modulo 1000000007 (109 + 7).
1256 1
4
13990 2
528
555 2
63
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.
题解
原题转化为 ans=a1 *(q^n-1)/(q-1) ,n == k
a1的值就是一个字符串中 0,5的位置。左边开始从0计数。 则依次计为 i0,i1,i2,i3.. a1 = 2^i0+2^i1+2^i2+2^i3 ...
其中q=2^strlen(s).
而难点是数太大了。。mod 运算比较麻烦。。
q^n此类用快速乘法幂解出答案。唯一剩下的就是 (c/d) mod q 时怎么计算。
我用的是模P乘法逆元
对于整数a、p,如果存在整数b,满足ab mod p =1,则说,b是a的模p乘法逆元。
定理:a存在模p的乘法逆元的充要条件是gcd(a,p) = 1
令(p*b)%mod=1,则有以下成立
对于(a/b)%mod= (a/b)*(p*b)%mod=(a*p)%mod=c
而对于(p*b)%mod=1,有 (p*b)%mod=1 <==> p*b-(p*b)/mod*mod=1
将 p用X代替,p*b/mod用Y代替,b用A表示,mod用B表示. 化成了AX+BY=1;
//#define ll long long
//inline ll extend_gcd(ll A,ll B,ll &X,ll &Y);
因此调用extend_gcd(b,mod,X,Y)即可解出答案X,即p,即逆元.
综上所以只用求出q-1的逆元即可。
代码:
/*
* @author ipqhjjybj
* @date 20130704
*
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#define clr(x,k) memset((x),(k),sizeof(x))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MAXN 10000001
#define ll long long
#define MOD 1000000007
using namespace std;
char s[100004];
int k;
//求逆元
//欧几里得扩展
//对(p*b)%mod=1
//调用extend_gcd(b,mod,X,Y),X即为p的解
inline ll extend_gcd(ll a,ll b,ll &x,ll &y){
ll ans,t;
if(b==0){x=1,y=0;return a;}
ans=extend_gcd(b,a%b,x,y);t=x,x=y,y=t-(a/b)*y;
return ans;
}
ll multipow(ll base,ll n){
ll r=1;
while(n){
if(n&1)
r=(r*base)%MOD;
base = (base*base)%MOD;
n>>=1;
}
return r;
}
int main(){
while(scanf("%s %d",s,&k)!=EOF){
ll a1=0;
int len=strlen(s);
for(int i=0;i<len;i++){
if(s[i]=='0'||s[i]=='5'){
a1=(a1+multipow(2,i))%MOD;
}
}
ll q = multipow(2,len);
ll q1 = (q+MOD-1)%MOD;
ll X,Y;
extend_gcd(q1,MOD,X,Y);
X = (X+MOD)%MOD;//防止X为负数
ll qn_x = (multipow(q,k)-1)*X%MOD;
ll ans = (a1*qn_x)%MOD;
cout<<ans<<endl;
}
return 0;
}
后来发现。如果把所有的i值全部提取出来。统一进行调用函数multipow。性能提升比较明显。。能从62MS降到42MS;