Codeforces 327C 快速幂+等比数列求和+乘法逆元

2024-03-30 02:58

本文主要是介绍Codeforces 327C 快速幂+等比数列求和+乘法逆元,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接:http://codeforces.com/problemset/problem/327/C
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 = |a|·k.

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

题意

有一个循环了n次字符串a,a中的字符均为数字。
现在要删去其中的若干字符(不能全删),使得最后剩下的数字是5的倍数。

思路

先说一个基本但必须用到的结论:若一个数是5的倍数,则它末位是5的倍数(即为5或0)。
设这个字符串为a[1]a[2]a[3]...a[p]...a[n]。
首先需要思考一个问题:以a[p]结尾的数有多少个。
答案是:2^(p-1)。
这个的推导过程很简单,这里就不赘述了。
并注意:数据过大,需要快速幂。然后要想一个问题:由于循环次数n过大,从前到后枚举一次不现实,需要用数学方法简化。
由于它循环n次每次都是相同的字符串,所以易得
以a[p]结尾的数个数+以a[p+len]结尾的数个数+...+a[p+len*(n-1)]
=2^(p-1)+2^(p+len-1)+...+2^(p+len*(n-1)-1)
=2^(p-1)*[2^0+2^len+...+2^(len*(n-1))]
然后用等比数列求和公式化简,得
原式=2^(p-1)*(2^(len*n)-1/2^len-1)。现在又面临一个更大的问题:
结果需要对10^9+7取模,但是在上式分母上下都是快速幂,取模后会有精度丢失的问题。
所以需要引进乘法逆元来完成。乘法逆元的定义是:如果ab≡1 (modp),则说b是mod p意义下的乘法逆元。
在此题中,需要求(a/b)%p的值,则设k是b的乘法逆元,则(a/b)%p=(a*k)%p。
这个等式的证明可以看这篇题解:
http://www.cnblogs.com/tiankonguse/archive/2012/08/14/2638949.html
而求b的乘法逆元可以运用费马小定理:
由b^(p-1)≡1 (modp),得b的乘法逆元是b^(p-2)。
所以问题就解决了。PS.变量最好用long long,如果一个int和一个long long相乘可能会出错。

代码

#include<stdio.h>
#include<cstring>
using namespace std;
const long long mod=1000000007;
long long fastpow(long long b,long long p,long long k) {b%=k;long long ret=1;while(p) {if(p&1) ret=(ret%k)*(b%k)%k;p>>=1;b=(b%k)*(b%k)%k;}return ret%mod;
}
char a[1000001];
int main() {
//  freopen("data.txt","r",stdin);long long k,len;gets(a);scanf("%I64d",&k);len=strlen(a);long long ans=0;for(int i=0; i<len; i++) {if(a[i]=='5' || a[i]=='0') {ans=(ans+fastpow(2,i,mod))%mod;}}long long tmp=fastpow(2,len,mod)%mod;long long p=fastpow(2,len*k,mod)%mod;tmp=((1-tmp)%mod+mod)%mod;tmp=fastpow(tmp,mod-2,mod);p=((1-p)%mod+mod)%mod;ans=(ans*p)%mod*tmp%mod;
//  if(a[0]=='8' && a[1]=='4')  printf("%I64d %I64d ",tmp,p);printf("%I64d",ans);return 0;
}
/*
27755776656210607832788619414635535178188775623838313967013958143619017005079991285469853503718562504927535176713879737569375166451462839457844835806559098448980069427607
151
*/

这篇关于Codeforces 327C 快速幂+等比数列求和+乘法逆元的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/860316

相关文章

hdu4828(卡特兰数+逆元)

这题的前几个数据分别为1,2,5,14,32......................然后确定这是个卡特兰数列 下面来介绍下卡特兰数,它的递推式为f[i+1] = f[i]*(4*n - 6)/n,其中f[2] = f[3] =1;f[4] = 2;f[5] = 14;f[6] = 32.................................. 但是这题的n太大了,所以要用到逆元,

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中,我们经常会遇到这样的情况:一不小心,桌面上的某个重要文件被删除了。这时,大多数人可能会感到惊慌失措,不知所措。 其实,不必过于担心,因为有很多方法可以帮助我们找回被删除的桌面文件。下面,就让我们一起来了解一下这些恢复桌面文件的方法吧。 一、使用撤销操作 如果我们刚刚删除了桌面上的文件,并且还没有进行其他操作,那么可以尝试使用撤销操作来恢复文件。在键盘上同时按下“C

hdu4869(逆元+求组合数)

//输入n,m,n表示翻牌的次数,m表示牌的数目,求经过n次操作后共有几种状态#include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdlib.h>#includ

hdu 4565 推倒公式+矩阵快速幂

题意 求下式的值: Sn=⌈ (a+b√)n⌉%m S_n = \lceil\ (a + \sqrt{b}) ^ n \rceil\% m 其中: 0<a,m<215 0< a, m < 2^{15} 0<b,n<231 0 < b, n < 2^{31} (a−1)2<b<a2 (a-1)^2< b < a^2 解析 令: An=(a+b√)n A_n = (a +

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

v0.dev快速开发

探索v0.dev:次世代开发者之利器 今之技艺日新月异,开发者之工具亦随之进步不辍。v0.dev者,新兴之开发者利器也,迅速引起众多开发者之瞩目。本文将引汝探究v0.dev之基本功能与优势,助汝速速上手,提升开发之效率。 何谓v0.dev? v0.dev者,现代化之开发者工具也,旨在简化并加速软件开发之过程。其集多种功能于一体,助开发者高效编写、测试及部署代码。无论汝为前端开发者、后端开发者

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja