[ARC064F] Rotated Palindromes


题意

给定一个整数N,请你求出有多少字符集为1到K之间整数的字符串,使得该字符串可以由一个长度为N的回文串循环移位后得到。所谓循环移位,就是把字符串的某个前缀(可以为空)移到字符串末尾,如"1221"循环移位可以得到"1221"、"2211"、"2112"、"1122"四个字符串。结果对$10^9+7$取模

题解

考试时花了差不多一个小时推了一个$O(n)$的式子,还妄想着能优化到$O(sqrt(n))$......

首先,考虑一个回文串对答案的贡献:

设其最小循环节长度为len。

其贡献就是len。

但是一个回文串的循环节必定也是回文串(想不明白可以看这个:abcabcabc)

所以对于len为偶数的情况,循环节可以从中间拆开,这就导致了互换前后段后相同的循环节,例如2112,1221会扩展出一样的结果,所以要此时贡献要除以2.

但对于长度为奇数的情况,由于有中间的一位,所以互换前后段后扩展出来的仍是不同的结果,所以不用除以2。

因为len相同的回文串对答案的贡献相同,所以对于每一个len,统计代表的回文串个数即可。

又因为len一定是n的因数(不然何来循环),所以直接根号n预处理出n的因数即可。

代码

#include 
#include 
#include 
#include 
using namespace std;
#define int long long
#define mod (int)1000000007
#define N 64000
vector vec;
int tot[N];
int pow(int base,int up)
{
	int ans=1;
	while(up)
	{
		if(up&1) ans*=base,ans%=mod;
		base*=base;
		base%=mod;
		up>>=1;
	}
	return ans;
}
signed main()
{
	int n,k,len;
	cin>>n>>k;
	len=sqrt(n);
	for(int i=1;i<=len;i++) if(n%i==0)//获取所有可能的循环节长度
	{
		vec.push_back(i);
		if(i!=n/i) vec.push_back(n/i);
	}
	sort(vec.begin(), vec.end());
	int ans=0;
	for(int i=0;i