CF327C 快速幂,费马小定理

链接:http://codeforces.com/problemset/problem/327/C

题意:给一串数,这串数重复k次,求去掉一些数后得到的新数能被5整除,问有多少种方法得到满足条件的数。

思路:要求能被5整除,则数的末位必然是0或5,求出原始串中0和5的位置,从0开始计数,位置为i1,i2,i3,,,in,则有a=2^i1+2^i2+...+2^in种方法。则在所有中的方法总数为:s=a*(q^n-1)/(q-1),q=2^len,len为原始串的长度。这个公式推一下就出来了。由于数据范围很大,所以要模1e9+7。在求幂的时候采用的是快速幂来做。除以(q-1)的话,求出它的逆元。由欧拉定理,(a,n)=1,a^phi(n)=1(mod n),a的逆为a^(phi(n)-1),n为素数时,phi(n)=n-1,所以a的逆为a^(n-2)%n.

#include<cstdio>
#include<cstring>
using namespace std;

typedef long long LL;
char a[100002];
int k;
int mod=1e9+7;

//LL fastmi(LL a, LL n)
//{
//    if (n == 0)
//        return 1;
//    else if (n % 2 == 1)
//        return (a * fastmi(a, n - 1)) % mod;
//    else
//    {
//        LL temp = fastmi(a, n / 2);
//        return (temp * temp) % mod;
//    }
//}
LL fastmi(LL a, LL b) {
    LL ans=1;
    while (b) {
        if (b&1){ans = (ans*a)%mod; b--;}
        b/=2; a = a * a % mod;
    }
    return ans;
}//由78s降到了46s
int main() { scanf("%s",a); scanf("%d",&k); int len=strlen(a); LL ans=0; for(int i=0; i<len; i++) if(a[i]=='0' || a[i]=='5') { ans=(ans+fastmi(2,i))%mod; } LL q=fastmi(2,len); LL p=fastmi(q,k)%mod; p=(p-1+mod)%mod; LL q1=(q-1+mod)%mod; ans=(ans*p)%mod; q1=fastmi(q1,mod-2)%mod;//欧拉定理 ans=(ans*q1)%mod; printf("%I64d ",ans); return 0; }

一开始不知道欧拉定理,公式也没化简,用循环直接求,自然T了。公式的话,能化简就化简,化简了可以看出一些东西来。

究竟是我抛弃了历史,还是历史遗弃了我。
原文地址:https://www.cnblogs.com/54zyq/p/3201224.html