题意:给出n,k.问有多少个长度为n的序列a满足:1<=a[i]<=k,并且序列a经过若干次循环左移能变成回文.
i.e:1,1,2,2 左移一次-> 1,2,2,1. n,k<=1e9.
当c为偶数时,重复数为一半,奇数时,无重复
设dp[x]为最小循环节长度为v[x]时有多少个回文序列.存在循环节为v[x]的序列有k^(v[x]/2)个
v[x]/2个任意 其中可能存在更小的循环节 DP时记得扣掉v[x]的约数
回文串的最小循环节长度为c 循环移位后最多得到c个不同序列.
i.e:1,1,2,2 左移一次-> 1,2,2,1. n,k<=1e9.
不考虑移位总共有k^(n/2)个回文,每个都可以操作n次,得到n个合法序列.如何去掉重复的?
回文串的循环节肯定为回文.按照回文串的最小循环节长度来更新答案
若回文串的最小循环节长度为c,经过c次操作后,得到c个序列当c为偶数时,重复数为一半,奇数时,无重复
设dp[x]为最小循环节长度为v[x]时有多少个回文序列.存在循环节为v[x]的序列有k^(v[x]/2)个
v[x]/2个任意 其中可能存在更小的循环节 DP时记得扣掉v[x]的约数
1e9内因子数大约为2000,O(d^2(n))
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int N=2e5+20;
vector<ll> v;
ll n,k,dp[2500];
ll powmod(ll x,ll n)
{
ll s=1;
while(n)
{
if(n&1)
s=(s*x)%mod;
n>>=1;
x=(x*x)%mod;
}
return s;
}
void init()
{
v.clear();
for(ll i=1;i*i<=n;i++)
{
if(n%i==0)
{
v.push_back(i);
if(i*i!=n)
v.push_back(n/i);
}
}
sort(v.begin(),v.end());
}
int main()
{
while(cin>>n>>k)
{
init();
ll ans=0;
for(int x=0;x<v.size();x++)
{
dp[x]=powmod(k,(v[x]+1)/2);
for(int y=0;y<x;y++)
{
if(v[x]%v[y]==0)
dp[x]=(dp[x]-dp[y]+mod)%mod;
}
if(v[x]%2)
ans=(ans+(dp[x]*v[x])%mod)%mod;
else
ans=(ans+(dp[x]*v[x]/2)%mod)%mod;
}
cout<<ans<<endl;
}
return 0;
}
回文串的最小循环节长度为c 循环移位后最多得到c个不同序列.