您的位置:首页 > 其它

CodeForces 327C Magic Five 二分求和 或 矩阵求和

2014-04-09 23:38 363 查看
这是个快速幂的题吧,,刚开始交的时候一直wa在第5组测试数据,,表示1000000007这个东西,一定要找个时间练练1000000007相关的题 T_T

题目大意:

给你一串数字, 然后给出一个数字k,表示有k次重复,从这个数字串中去掉一些数(也可以不去掉任何数)要求剩下的数能被5整除,剩下的数可以有前导零,不同的去除方法即使得到相同的数字串也算不同的方法。 求可能的方法的数量,结果模上1000000007。

大致思路:

首先考虑不进行k次重复时,这个数字串要使得结尾是0或5,那么,在被作为最后以为的0或5之前的数可以去掉或者不去掉,在其之后的数必须都去掉。

那么,以一个数字串的第 i 位作为结尾的可能性就有 2 ^ i 种, 由于数字串重复,记字符串未重复时长度为 n, 那么数字串的第 i + n, i+ 2*n, i + 3*n ,,,,,, i + (k - 1)*n都可以作为结尾。

对于原数字串,第 i 位作为结尾, i + n, i + 2*n, i + 3*n, i + 4*n,,,,i + k*n 的可能方式有 (2 ^ i ) * (2^0 + 2^n + 2^(2*n) + 2^(3*n) + ....+ 2^((k - 1)*n); 

对于原数字串统计它的 2 ^ i 的总和就可以了。

这里给出两种做法

解法一:

将 (2^0 + 2^n + 2^(2*n) + 2^(3*n) + ....+ 2^((k - 1)*n) 每次二分变为:

((2^0 + 2^n + 2^(2*n) + 2^(3*n) + ....+ 2^((k - 1)/2)*n))  * (1 + 2 ^ ((((k - 1)/2) + 1)*n))

对于每个2的次方都用快速幂,代码如下:

Result : Accepted  Memory :  300 KB    Time :  62 ms

/*
* Author : Gatevin
* Time : 2014.4.9 22:07
* Problem : CodeForces 327C Magic Five
* Tag : quick_pow, math, geometric sequence
*/

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
typedef long long lint;
using namespace std;
const int mod = 1000000007;
string s;
int times;

lint quick_pow(lint base, lint pow)//快速幂
{
lint rep = 1;
while(pow)
{
if(pow & 1)
{
rep = (rep * base)%mod;
}
pow >>= 1;
base = (base*base)%mod;
}
return rep;
}

lint two_divide(lint base, lint len)//对于要求和的式子每次二分,左右两边有一个倍数关系,有可能多一项
{
if(len == 1) return 1;
lint tmp = two_divide(base, len >> 1);
lint rep = ((1 + quick_pow(base, len >> 1))*tmp)%mod;
if(len & 1)//多一项时
{
rep = (rep + quick_pow(base, len - 1))%mod;
}
return rep;
}

int main()
{
cin>>s>>times;
lint ans = 0;
for(int i = 0; i <= s.size() - 1; i++)
{
if(s[i] == '0' || s[i] == '5')
{
ans = ( ans + quick_pow(2,i))%mod;//式子的一部分
}
}
ans = (ans*two_divide(quick_pow(2,s.size()), times))%mod;//乘上另一部分
cout<<ans<<endl;
return 0;
}


解法二:

采用矩阵求等比数列的和

这个还是看经验问题吧,,,

Result : Accepted    Memory : 300 KB   Time : 62ms

/*
* Author : Gatevin
* Time : 2014.4.9  23:36
* Problem : CodeForces 327C  Magic Five
* Tag : Matrix, math, geometric progression
*/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long lint;
const lint mod = 1000000007;
struct Matrix
{
lint p[2][2];
Matrix()
{
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
p[i][j] = (i == j) ? 1 : 0;
}
}
}
};

Matrix Mutiple(Matrix A, Matrix B)
{
Matrix C;
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
C.p[i][j] = 0;
for(int k = 0; k < 2; k++)
{
C.p[i][j] = (C.p[i][j] + A.p[i][k]*B.p[k][j]%mod)%mod;
}
}
}
return C;
}

Matrix quick_pow(Matrix A, lint pow)//矩阵快速幂
{
Matrix I;
while(pow)
{
if(pow & 1)
{
I = Mutiple(I, A);
}
pow >>= 1;
A = Mutiple(A, A);
}
return I;
}

lint quick_pow(lint base, lint pow)
{
lint ret = 1;
while(pow)
{
if(pow & 1)
{
ret = (ret * base)%mod;
}
pow >>= 1;
base = (base* base)%mod;
}
return ret;
}

string s;
lint times;

int main()
{
cin>>s>>times;
lint ans = 0;
for(lint i = 0; i <= s.size() - 1; i++)
{
if(s[i] == '0' || s[i] == '5')
{
ans = (ans + quick_pow(2, i))%mod;//统计s中可以的可能数
}
}
lint base = quick_pow(2, s.size());
Matrix I;
I.p[0][0] = 1;
I.p[0][1] = 0;
I.p[1][0] = 1;
I.p[1][1] = base;
I = quick_pow(I, times);
cout<<(ans*I.p[1][0])%mod<<endl;
return 0;
}


好了,就写到这里吧,,

刚才一个很好的高中同学有些情绪低落,中途去安慰了一下,讨论了一下人生观,希望她能挺过这些困难,走向灿烂的阳光~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息