★问题描述:
对于长度为n、由小写字母组成的(不一定要用所有字母)字符串s,如果存在一个字符串t,t≠s,使得s可以由t重复若干次得到,那么我们称s具有周期性。
周期性字符串计数问题是指对于给定的n,求有多少个长度为n的周期性字符串。注意串中只包含26个小写字母。
★编程任务:
输入正整数n,试设计一个算法,计算长度为n的字符串中,具有周期性的字符串一共有多少个。
题解
设g[n]表示长度为n的字符串总数。
设f[n]表示周期为n的非周期性字符串总数。
则gn=∑d|nfd
求解目标:∑d|n,d<nfd 即 g[n]-f[n] 。
g[n]乘法原理O(1)可解。
f[n]用莫比乌斯反演搞一搞。
其实化简一下g[n]都不要求。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define R register
#define ll long long
#define mod 1000000007
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
using namespace std;
ll N,pr[1000000];
ll pow(ll k)
{
ll base=26,ans=1;
while(k)
{
if(k&1)ans=ans*base%mod;
base=base*base%mod,k>>=1;
}
return ans;
}
int miu(ll k)
{
int end=(int)sqrt(k),cnt,ans=1;
for(int i=2;i<=end;i++)if(k%i==0)
{
cnt=0;
while(k%i==0)cnt++,k/=i;
if(cnt>1)return 0;
else ans=-ans;
}
if(k>1)ans=-ans;
return ans;
}
int main()
{
R int end,pt=0,i;
R ll sum;
scanf(LL,&N);end=(int)sqrt(N);
for(i=1;i<=end;++i)if(N%i==0)
{
pr[pt++]=i;
if((ll)i*i!=N&&i!=1)pr[pt++]=N/i;
}
for(sum=0,i=0;i<pt;++i)
{
sum=(sum+(mod-pow(pr[i])*(ll)miu(N/pr[i])))%mod;
}
printf(LL,sum);
return 0;
}