求有多少个序列满足以下条件:
1. 序列有n位;
2. 序列的每位为1~m之间的整数;
3. 这个序列经过旋转以后可以变成一个回文串;
这是一个悲惨的故事…..想了一天多,一直在想怎么减掉不合法的,最后一怒之下瞄了一眼(真的就是瞄一眼)标程,咦标称是直接统计耶,下一瞬间:
WOC这不是大水题吗
对于每个回文串,假设它旋转了x次以后第一次变成回文的,那么它对答案就有x的贡献(转0次~转x-1次),
考虑怎样的回文串转x次会变成回文的,(先假设x为n的约数)
把n切成(n/x)段,也就是每段有x个,
如果n/x为奇数,那么,只有这(n/x)段都相同且为回文的,它转x后还是回文的,
比如:(x=3,n=9)121 121 121;
如果n/x为偶数,那么, 这一段可以为任意,保证每(2x)位为一个回文串即可,
比如:(x=2,n=8)12 21 12 21;
根据上面计算方法,可得出,一个回文串如果转x次为回文串,那么转x的约数次也为回文串,(比如:转6次变成回文的,那么转12、18次也是回文的)
我们真正要统计的是,对于每个回文串,假设它旋转了x次以后第一次变成回文的,所以要减掉重复的,
显然,如果x不为n的约数,贡献为0,
复杂度可以参考枚举子集的复杂度,即 O(3x) O ( 3 x ) (大概),不会很大。
#include
#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
using namespace std;
typedef long long LL;
const int N=100500,mo=1e9+7;
int m,n;
int fj[N][2],fj0;
int d[N];
LL ans;
map<int,int>f;
LL ksm(LL q,int w)
{
LL ans=1;
for(;w;w>>=1,q=q*q%mo)if(w&1)ans=ans*q%mo;
return ans;
}
int ss1(int q,int w,int e)
{
if(q>w)return f[e];
int ans=ss1(q+1,w,e);
fo(i,1,d[q])((ans+=ss1(q+1,w,(e=e*fj[q][0])))>=mo?ans-=mo:0);
return ans;
}
void ss(int q,int e)
{
if(q>fj0)
{
LL t=(((n/e)%2?ksm(m,(e+1)>>1):ksm(m,e))-ss1(1,q,1)+mo)%mo;
f[e]=t;
ans=(ans+t*e)%mo;
return;
}
d[q]=0;ss(q+1,e);
fo(i,1,fj[q][1])d[q]=i,ss(q+1,(e*=fj[q][0]));
}
int main()
{
int q,w;
scanf("%d%d",&n,&m);
if(n==1)return printf("%d\n",m),0;
q=n;
for(int i=2;i*i<=q;++i)if(q%i==0)
{
for(fj[++fj0][0]=i;!(q%i);++fj[fj0][1],q/=i);
}
if(q>1)fj[++fj0][0]=q,fj[fj0][1]=1;
ss(1,1);
printf("%lld\n",(ans+mo)%mo);
return 0;
}