链接:https://www.nowcoder.com/acm/contest/106/B
来源:牛客网
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
It’s universally acknowledged that there’re innumerable trees in the campus of HUST.
Note that when we transfer the string to a integer, we ignore the leading zeros. For example, the string “00055” will be seen as 55. And also pay attention that two ways are considered different if the removed trees are different. The result can be very large, so printing the answer (mod 1000000007) is enough. And additionally, Xiao Ming can't cut down all trees.
输入描述:
The first line contains a single integer K, which indicates that the tree string is the initial string repeating K times.
The second line is the initial string S.
输出描述:
A single integer, the number of ways to remove trees mod 1000000007.
输入
1 100
输出
6
说明
Initially, the sequence is ‘100’. There are 6 ways: 100 1_0 10_ _00 __0 _0_
输入
3 125390
输出
149796
这个是队友写的代码,其实当时我找到规律了,但是就是等比数列的除法取模这不会写,然后好像是要用到 除法取模的算法, 这里先贴下代码吧,等我搞懂了再回来讲解
(后来搞懂了,自己写的代码贴在后面)
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;
char s[maxn];
vector<int> v;
void find0_5()
{
for(int i=0;s[i]!='\0';i++)
{
if(s[i]=='0'||s[i]=='5')
v.push_back(i);
}
}
long long fapow(long long a,int b)
{
long long ans=1;
while(b>0)
{
if(b&1)
{
ans=(ans*a)%mod;
}
a=(a*a)%mod;
b=b>>1;
}
return ans;
}
int main()
{
int k;
scanf("%d%s",&k,s);
find0_5();
int len=strlen(s);
long long ans=0;
for(int j=0;j<v.size();j++)
{
ans=(ans+fapow(2,v[j]))%mod;
}
long long q=fapow(2,len)%mod;
ans=(ans*(fapow(q,k)-1))%mod;
int m=fapow(q-1,mod-2);
ans=(ans*m)%mod;
printf("%lld",ans);
return 0;
}
好了,其实也就是除法的取模阻碍了我,那么先补充一下知识点吧。
如果要求 (a/b)%mod 是不能直接求的, 那么我们找到一个数c,这个数叫b的逆元,那么就有 (a/b)%mod = (a*c)%mod ,所以我们只需找到c就行了,找逆元有很多算法,感觉费马小定理最简答。
下面是我写的测试代码
就是求a/b;我就不说了
然后做这个题还有个问题就是减法的模,也要注意下,比如 8-3对6的模,结果是5,但是如果直接 8%6-3%6 结果就错了,所以减法的模实际上还要+mod,即 (8%6-3%6+6)%6,之所以说这个是因为等比数列公式的分子中有相减的,由此得到了启发。
然后本篇文章没有讲思路,就是写了乘法逆元的一个小应用,思路的话,大家就仔细画一下样例2的数,然后找规律,算结果对了之后就懂了
下面是我写的代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
typedef long long ll;
using namespace std;
const int mod = 1e9+7;
const int maxn = 1e5+4;
ll f( ll a,ll b )
{
ll ans = 1;
while( b )
{
if( b&1 )
ans = (ans*a)%mod;
b = b>>1;
a = (a*a)%mod;
}
return ans;
}
char s[maxn];
int k;
vector<int> v;
int main()
{
cin>>k;
scanf("%s",s);
int len = strlen(s);
for( int i = 0 ; i < len ; i++ )
if( s[i] == '0' || s[i] == '5' )
v.push_back(i);
ll ans = 0;
ll q = f(2,len);
ll qk = f(q,k);
for( int i = 0 ; i< v.size() ; i++ )
{
ans = ( mod+(ans+f(2,v[i]+k*len) )%mod-f(2,v[i]) )%mod;
}
ll c = f(q-1,mod-2);
cout<<(ans*c)%mod<<endl;
return 0;
}
等比数列改了一下的代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
typedef long long ll;
using namespace std;
const int mod = 1e9+7;
const int maxn = 1e5+4;
ll f( ll a,ll b )
{
ll ans = 1;
while( b )
{
if( b&1 )
ans = (ans*a)%mod;
b = b>>1;
a = (a*a)%mod;
}
return ans;
}
char s[maxn];
int k;
vector<int> v;
int main()
{
cin>>k;
scanf("%s",s);
int len = strlen(s);
for( int i = 0 ; i < len ; i++ )
if( s[i] == '0' || s[i] == '5' )
v.push_back(i);
ll ans = 0;
ll q = f(2,len);
ll qk = f(q,k);
for( int i = 0 ; i< v.size() ; i++ )
{
ll temp = f(2,v[i]);
ans = (ans+(temp*(qk-1))%mod )%mod;
}
ll c = f(q-1,mod-2);
cout<<(ans*c)%mod<<endl;
return 0;
}