Codeforces Round #191 (Div. 2) C magic five

题目大意:给定一个字符串 s,长度 len 最长是100000,接着输入一个整数 k,k 最大是10的9次方,求 k 个 s 连接在一起得到一个串,设为str,从str中删除一些数(也可以不删,但不能全部删除),使得得到的数能够整除5,求共有多少种删除方式,注意:被删除的数的位置不同,算做不同的删除方式。


解题思路:我们知道如果一个数能够整除5,那它的个位数一定是 0 或者 5 。因此我们需要在串 s 中找到每个 0 或者 5 的位置,假设第一个找到的位置为 i ,易证明,以此位置的0(或者5)为尾数共有 2 的 i 次方种删除方式,进而可得由 k 个 s 组成的串 str 中有 2 的 i 次幂 + 2 的 (i+len*1)次幂 + …… + 2 的 [ i + len *(k-1)] 次幂,易发现这是一个首项为2 的 i 次幂,公比为 2 的 len 次幂的等比数列求和,我们用快速幂和乘法逆元解决。所以对串 s 中每个0 或者5 进行计算并将结果相加,即可得到最后答案。


模p乘法逆元对于整数a、p,如果存在整数b,满足ab mod p =1,则说,b是a的模p乘法逆元。

如果gcd(a,p)=d,则存在m,n,使得d = ma + np,称这种关系为a、b组合整数d,m,n称为组合系数。当d=1时,有 ma + nb = 1 ,此时可以看出m是a模p的乘法逆元,n是p模a的乘法逆元。 故可用扩展欧几里得求乘法逆元。但算出来的m,n可能为负数,最后要把它转化为正数。

定理:a存在模p的乘法逆元的充要条件是gcd(a,p) = 1

证明:
首先证明充分性
如果gcd(a,p) = 1,根据欧拉定理,aφ(p) ≡ 1 mod p,因此
显然aφ(p)-1 mod p是a的模p乘法逆元。
再证明必要性
假设存在a模p的乘法逆元为b
ab ≡ 1 mod p
则ab = kp +1    ,所以1 = ab - kp
因为gcd(a,p) = d
所以d | 1
所以d只能为1
 
 
代码如下:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>


#define  N 100005
typedef  long long ll;
const int  mod=1e9+7;
ll k;
char str[N];


void extgcd(ll a, ll b, ll &x, ll &y)
{
         if(b==0)
         {
                  x=1;
                  y=0;
                  return;
         }
         extgcd(b,a%b,x,y);
         ll t=x;x=y;y=t-a/b*y;
}


ll  Pow(ll a,ll b)
{
        ll ret=1;
        while(b)
        {
                 if(b&1) ret=ret*a%mod;
                 a=a*a%mod; b>>=1;
        }
        return ret;
}


int  main()
{
         while(~scanf("%s %d",str,&k))
         {


                ll len=strlen(str);
                ll u=( Pow( 2, len * k ) - 1 + mod ) % mod;
                ll q=( Pow( 2, len ) - 1 + mod ) % mod;
                ll x,y,ans=0;
                extgcd(q,mod,x,y);
                while(x<0)  x+=mod;
                for(int i=0;i<len;i++)
                {
                         if(str[i]=='0' || str[i]=='5')
                         {
                               ans = (ans + (Pow(2,i) % mod * u % mod * x %mod) ) %mod;
                         }
                }
                printf("%I64d\n",ans);
         }
         return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值