1. 程式人生 > >【2019 1月集訓 Day1】迴文的字尾

【2019 1月集訓 Day1】迴文的字尾

題意:

  給定 n,s,求有多少個字符集大小為 s ,長度為 n 的字串,使得其不存在一個長度大於 1 迴文字尾

  答案對 m 取模。

分析:

  考場見到計數題的鏈式反應,想寫暴力—>暴力難寫—>不會暴力—>棄療—>爆零。

  今天考試也不例外。但是逐漸思想過於摸化,沒想到今天T2這麼簡單的一個遞推,竟然不會寫,我好弱啊,大概是學廢了。

  對於這道題目,我們想到,字尾其實就是字首(把字串倒過來即可)我們設f[i]表示長度為i的滿足題意的最長迴文字首是1的字串有多少個,f[0]=1,在轉移時,我們啥都不考慮,直接加一個字母。

  但是可能原串是這樣的,最長迴文字首長度為1,我們加了一個字母之後,突然最長迴文字首長度就變成了i,比如“abbbbbb”最長迴文字首是1,但是,假如我們加入一個a,那麼這個長度立刻就變成了8,我們就要把不和法的減去,所以考慮長度為p的迴文串(不存在一個大於1的迴文串是它的字首)的數目,其實我們把把半個串確定了,整個迴文串就確定了。

  所以方案數是f[ceil(i/2)],(ceil()函式代表向上取整)。

  最終的遞推式子就是f[i]=f[i-1]*s-f[ceil(i/2)];

  別忘取模……

程式碼:

 

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #define ll long long
 7 using namespace std;
 8
const int N=10000005; 9 ll f[N],m,n,k,s,w; 10 int main(){ 11 scanf("%lld%lld%lld",&n,&s,&m); 12 f[0]=1;for(int i=1;i<=n;i++) 13 f[i]=(f[i-1]*s-f[(i+1)>>1])%m; 14 printf("%lld\n",f[n]%m); 15 return 0; 16 }
dp