Codeforces 327C 乘法逆元 + 费马小定理 || 等比数列二分求和取模

来源:互联网 发布:怎么在淘宝买东西便宜 编辑:程序博客网 时间:2024/05/29 12:17
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 containingn 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 by5. Note that, the resulting number may contain leading zeros.

Now Iahub wants to count the number of ways he can obtain magic number, modulo1000000007 (109 + 7). Two ways are different, if the set of deleted positions ins 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 integerk (1 ≤ k ≤ 109). The plates is formed by concatenating k copies of a together. That isn = |ak.

Output

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

Examples
Input
12561
Output
4
Input
139902
Output
528
Input
5552
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 ofa. The actual plate is 1399013990.

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



Well, 这道题题意是要你求一个重复n次的字符串删掉一些数字后组成的数字能被5整除的个数。那么我们可以这么想,能被5整除的数对10取余必定是0 或者 5,也就是说,删除一些数字后,个位一定是0或者5。 那么我们扫一遍,每当str[i] == '0' || str[i] == '5' 时 我们算一算有多少种做法。

对于重复一次的字符串的每一个等于 0 或者 5 的位置来说,有2^(i - 1)(ps: 字符串 [1, len])种删法(删0个,删1个,删2个...... 删 i - 1 个)

那对于重复n次的呢?

有sum[i] = 2^(i - 1) + 2 ^ (i - 1 + len) + 2 ^ (i - 1 + 2 * len)  + ...... + 2 ^ (i - 1 + (n - 1) * len)

令 A = 2 ^ (i - 1),  q = 2 ^ len,上面就等于sum[i] = A * q ^ 0 + A * q ^ 1 + ....... + A * q ^ (n - 1)

===>   sum[i] = A * (q ^ 0 + q ^ 1 + ... + q ^ (n - 1)) = A * (q ^ n     -   1) / (q - 1)

等比数列。那么答案就是所有sum[i]的和。


下面说两种方法解决这种题:乘法逆元 + 费马小定理   &&   等比数列二分求和取余


乘法逆元 + 费马小定理:

关于取余运算不用多说,所有你觉得可能超过MOD的加法乘法都加上取余就行了(a + b) % c = (a % c + b % c) % c, (a * b) % c = (a % c * b % c) % c

肯定有人说直接用等比数列求和公式就行了啊。。。那行吧,别往下看了。

因为公式的计算会使中间结果超int 甚至 long long 范围,会错。

求 A * (q ^ n - 1) / (q - 1) % MOD    的时候注意有除法,在取余这个运算里没有 (a / b) % c = (a % c / b % c) % c,所以我们需要找个其他办法,那就是逆元

定义: a * b = 1 (mod c) 那么b就是a的逆元,在取余这个二元关系中。

性质: (a / b) % c == (a * bt) % c   其中bt是b的逆元。

这里需要求(q - 1) 的逆元, 注意到MOD是素数, 也就自然而然想到费马小定理 ====> a ^ (p - 1) = 1 (mod p) 其中p是素数

那么a的逆元at = a ^ (p - 2)  所以 (q - 1) 的逆元就是 (q - 1) ^ (MOD - 2)

剩下的就好办了。

以下代码亲测124ms,比二分慢了近一倍,因为有重复计算。。

<span style="font-size:18px;">/*************************************************************************    > File Name: 327C.cpp    > Author: Triose    > Mail: Triose@163.com     > Created Time: 2016年08月01日 星期一 08时30分55秒 ************************************************************************///#include<bits/stdc++.h>#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#include<vector>#include<queue>#include<stack>#include<iterator>#include<math.h>#include<stdlib.h>#include<time.h>#include<map>#include<set>using namespace std;//#define ONLINE_JUDGE#define eps 1e-8#define inf 0x3f3f3f3f#define INF 0x7fffffff#define INFL 0x3f3f3f3f3f3f3f3fLL#define enter putchar(10)#define rep(i,a,b) for(int i = (a); i < (b); ++i)#define repe(i,a,b) for(int i = (a); i <= (b); ++i)#define mem(a,b) (memset((a),b,sizeof(a)))#define sf(a) scanf("%d",&a)#define sfI(a) scanf("%I64d",&a)#define sfd(a,b) scanf("%d%d",&a,&b)#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)#define sfs(a) scanf("%s",a)#define pf(a) printf("%d\n",a)#define pfd(a,b) printf("%d %d\n",a,b)#define pfP(a) printf("%d %d\n",a.fi,a.se)#define pfs(a) printf("%s\n",a)#define pfI(a) printf("%I64d\n",a)#define ds(a) int a; sf(a)#define PR(a,b) pair<a,b>#define fi first#define se second#define LL long long#define DB doubleconst double PI = acos(-1.0);const double E = exp(1.0);template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }template<class T> inline T Min(T a, T b) { return a < b ? a : b; }template<class T> inline T Max(T a, T b) { return a > b ? a : b; }int n, m;const LL MOD = (1e+9) + 7;#define N 100010char str[N];LL len, q;LL C;LL PowMod(LL a, LL t, LL mod) {    LL res = 1;     LL base = a % mod;    while(t) {if(t & 1)    res = (res * base) % mod;base = (base * base) % mod;t >>= 1;    }    return res;}LL get_mod(int pos) {    LL A = PowMod(2, pos - 1, MOD);    LL B = PowMod(q, n, MOD);    B = (B - 1 + MOD) % MOD;    return (((A * B) % MOD) * C) % MOD;}int main() {#ifndef ONLINE_JUDGE    freopen("in.txt","r",stdin);//  freopen("Out.txt", "w", stdout);#endif    while(~sfs(str + 1)) {sf(n);len = strlen(str + 1);q = PowMod(2, len, MOD);LL ans = 0;C = PowMod(q - 1, MOD - 2, MOD);//逆元repe(i, 1, len) {    if(str[i] == '5' || str[i] == '0') {ans = (ans + get_mod(i)) % MOD;    }}pfI(ans);    }    return 0;}</span>

现在贴改进了的:B这个数从头到尾都没变,所以一开始就计算出来就好了。。

<span style="font-size:18px;">/*************************************************************************    > File Name: 327C.cpp    > Author: Triose    > Mail: Triose@163.com     > Created Time: 2016年08月01日 星期一 08时30分55秒 ************************************************************************///#include<bits/stdc++.h>#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#include<vector>#include<queue>#include<stack>#include<iterator>#include<math.h>#include<stdlib.h>#include<time.h>#include<map>#include<set>using namespace std;//#define ONLINE_JUDGE#define eps 1e-8#define inf 0x3f3f3f3f#define INF 0x7fffffff#define INFL 0x3f3f3f3f3f3f3f3fLL#define enter putchar(10)#define rep(i,a,b) for(int i = (a); i < (b); ++i)#define repe(i,a,b) for(int i = (a); i <= (b); ++i)#define mem(a,b) (memset((a),b,sizeof(a)))#define sf(a) scanf("%d",&a)#define sfI(a) scanf("%I64d",&a)#define sfd(a,b) scanf("%d%d",&a,&b)#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)#define sfs(a) scanf("%s",a)#define pf(a) printf("%d\n",a)#define pfd(a,b) printf("%d %d\n",a,b)#define pfP(a) printf("%d %d\n",a.fi,a.se)#define pfs(a) printf("%s\n",a)#define pfI(a) printf("%I64d\n",a)#define ds(a) int a; sf(a)#define PR(a,b) pair<a,b>#define fi first#define se second#define LL long long#define DB doubleconst double PI = acos(-1.0);const double E = exp(1.0);template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }template<class T> inline T Min(T a, T b) { return a < b ? a : b; }template<class T> inline T Max(T a, T b) { return a > b ? a : b; }int n, m;const LL MOD = (1e+9) + 7;#define N 100010char str[N];LL len, q;LL B, C;LL PowMod(LL a, LL t, LL mod) {    LL res = 1;     LL base = a % mod;    while(t) {if(t & 1)    res = (res * base) % mod;base = (base * base) % mod;t >>= 1;    }    return res;}LL get_mod(int pos) {    LL A = PowMod(2, pos - 1, MOD);    return (((A * B) % MOD) * C) % MOD;}int main() {#ifndef ONLINE_JUDGE    freopen("in.txt","r",stdin);//  freopen("Out.txt", "w", stdout);#endif    while(~sfs(str + 1)) {sf(n);len = strlen(str + 1);q = PowMod(2, len, MOD);LL ans = 0;C = PowMod(q - 1, MOD - 2, MOD);    // q - 1 % MOD 的乘法逆元B = PowMod(q, n, MOD);B = (B - 1 + MOD) % MOD;repe(i, 1, len) {    if(str[i] == '5' || str[i] == '0') {ans = (ans + get_mod(i)) % MOD;    }}pfI(ans);    }    return 0;}</span>



下面说等比数列二分求和取模:


sum(n) = q ^ 1 + q ^ 2 + ...... + q ^ n

n为偶数:

sum(n) = q ^ 1 + q ^ 2 + ... + q ^ (n / 2) + q ^ ((n / 2) + 1) + q ^ ((n / 2) + 2) + ... + q ^ (n / 2 + n / 2)

        = (1 + q ^ (n / 2)) * sum(n / 2)

n为奇数:

sum(n) = q ^ 1 + q ^ 2 + ... + q ^ ((n - 1) / 2) + q ^ ((n - 1) / 2   + 1) + ... + q ^ ((n - 1) / 2 + (n - 1) / 2) + q ^ (n)

        = (1 + q ^ ((n - 1) / 2) ) * sum((n - 1) / 2)    +    q ^ n

所以:

<span style="font-size:18px;">LL PowMod(LL A, LL T, LL mod) {// A ^ T % mod    LL res = 1;    LL base = A % mod;    while(T) {if(T & 1)     res = (res * base) % mod;base = (base * base) % mod;T >>= 1;    }    return res;}LL PowSumMod(LL q, LL T, LL mod) {// (q ^ 1 + .... + q ^ T) % mod    if(T == 0) return 0;    if(T == 1) return q % mod;    if(T % 2 == 0) {return (((PowMod(q, T / 2, mod) + 1) % mod) * PowSumMod(q, T / 2, mod)) % mod;    }    else {return ((((PowMod(q, T / 2, mod) + 1) % mod) * PowSumMod(q, T / 2, mod)) % mod + PowMod(q, T, mod)) % mod;    }}</span>

接下来贴代码:62ms

<span style="font-size:18px;">/*************************************************************************    > File Name: 327C1.cpp    > Author: Triose    > Mail: Triose@163.com     > Created Time: 2016年08月01日 星期一 10时29分31秒 ************************************************************************///#include<bits/stdc++.h>#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#include<vector>#include<queue>#include<stack>#include<iterator>#include<math.h>#include<stdlib.h>#include<time.h>#include<map>#include<set>using namespace std;//#define ONLINE_JUDGE#define eps 1e-8#define inf 0x3f3f3f3f#define INF 0x7fffffff#define INFL 0x3f3f3f3f3f3f3f3fLL#define enter putchar(10)#define rep(i,a,b) for(int i = (a); i < (b); ++i)#define repe(i,a,b) for(int i = (a); i <= (b); ++i)#define mem(a,b) (memset((a),b,sizeof(a)))#define sf(a) scanf("%d",&a)#define sfI(a) scanf("%I64d",&a)#define sfd(a,b) scanf("%d%d",&a,&b)#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)#define sfs(a) scanf("%s",a)#define pf(a) printf("%d\n",a)#define pfd(a,b) printf("%d %d\n",a,b)#define pfP(a) printf("%d %d\n",a.fi,a.se)#define pfs(a) printf("%s\n",a)#define pfI(a) printf("%I64d\n",a)#define ds(a) int a; sf(a)#define PR(a,b) pair<a,b>#define fi first#define se second#define LL long long#define DB doubleconst double PI = acos(-1.0);const double E = exp(1.0);template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }template<class T> inline T Min(T a, T b) { return a < b ? a : b; }template<class T> inline T Max(T a, T b) { return a > b ? a : b; }int n, m;#define N 100010const LL MOD = (1e+9) + 7;char str[N];int len;LL PowMod(LL A, LL T, LL mod) {// A ^ T % mod    LL res = 1;    LL base = A % mod;    while(T) {if(T & 1)     res = (res * base) % mod;base = (base * base) % mod;T >>= 1;    }    return res;}LL PowSumMod(LL q, LL T, LL mod) {// (q ^ 1 + .... + q ^ T) % mod    if(T == 0) return 0;    if(T == 1) return q % mod;    if(T % 2 == 0) {return (((PowMod(q, T / 2, mod) + 1) % mod) * PowSumMod(q, T / 2, mod)) % mod;    }    else {return ((((PowMod(q, T / 2, mod) + 1) % mod) * PowSumMod(q, T / 2, mod)) % mod + PowMod(q, T, mod)) % mod;    }}int main() {#ifndef ONLINE_JUDGE    freopen("in.txt","r",stdin);//  freopen("Out.txt", "w", stdout);#endif    while(~sfs(str + 1)) {sf(n);len = strlen(str + 1);LL q = PowMod(2, len, MOD);LL sum = PowSumMod(q, n - 1, MOD);sum = (sum + 1) % MOD;LL ans = 0;repe(i, 1, len) {    if(str[i] == '0' || str[i] == '5') {LL tmp = PowMod(2LL, i - 1, MOD);tmp = (tmp * sum) % MOD;ans = (ans + tmp) % MOD;    }}pfI(ans);    }    return 0;}</span>





0 0