【AtCoder】【ARC064F】Rotated Palindromes

Description

求有多少個序列滿足以下條件:
1. 序列有n位;
2. 序列的每位爲1~m之間的整數;
3. 這個序列經過旋轉以後可以變成一個迴文串;

Solution

這是一個悲慘的故事…..想了一天多,一直在想怎麼減掉不合法的,最後一怒之下瞄了一眼(真的就是瞄一眼)標程,咦標稱是直接統計耶,下一瞬間:
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) (大概),不會很大。

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#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;
}
發佈了366 篇原創文章 · 獲贊 58 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章