SnackDown 2019 - Online Elimination Round Suffix Palindromes

原题链接.

没上OEIS真的是亏了。

题目大意:

问有多少个字符集大小为|S|的长度为n的字符串,不存在一个长度大于1的回文后缀。

1<=n<=1000

1<=|S|

题解:

这种题一看就要容斥原理

首先总方案数是S^n

减去后缀是回文串的,但是我们发现直接减肯定减重。

不妨设 f [ i ] f[i] f[i]表示长度为i的回文串,且它也不存在长度大于1的回文后缀的方案数。

A n s = S n − ∑ i = 2 n f [ i ] ∗ S n − i Ans=S^n-\sum_{i=2}^nf[i]*S^{n-i} Ans=Sni=2nf[i]Sni

那么 f [ i ] f[i] f[i]如何计算呢?

显然可以继续容斥,即总数减去有回文后缀,且这个回文后缀没有大于1的回文后缀。

m = ( n + 1 ) / 2 m=(n+1)/2 m=(n+1)/2
f [ n ] = S m − ∑ i = 1 m f [ i ] ∗ S m − i f[n]=S^m-\sum_{i=1}^mf[i]*S^{m-i} f[n]=Smi=1mf[i]Smi

为什么不用考虑i>m的情况呢,

因为如果后缀i>m是回文的,这个后缀一定有一个大于1的回文后缀。

证明:
因为原串是回文的:
所以s[i…2m-i]是回文的,又因为后缀i是回文的,所以长度是i-(2m-i)+1的后缀也是回文的。

i-(2m-i)+1=2(i-m)+1
因为i>m所以2(i-m)+1>=3

因此后缀i一定还存在长度大于1的回文后缀。

感觉最后的这个点挺难想的,卡了一会儿,毕竟这题Samjia做了1h也没有做出来(小骄傲~)

Code:

#include
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;

const int N = 1e3 + 5;

int n, s, mo;
ll f[N], a[N], ans;

int main() {
	scanf("%d %d %d", &n, &s, &mo);
	a[0] = 1; fo(i, 1, n) a[i] = a[i - 1] * s % mo;
	fo(i, 2, n) {
		int m = i + 1 >> 1;
		f[i] = a[m];
		fo(j, 2, m) f[i] = (f[i] - f[j] * a[m - j] % mo + mo) % mo;
	}
	ans = a[n];
	fo(i, 2, n) ans = (ans - a[n - i] * f[i] % mo + mo) % mo;
	printf("%lld", ans);
} 

你可能感兴趣的:(动态规划)