Reverse and Compare
这道题看起来像回文串的题,但却不是。。。。
我们考虑
s
i
和
s
j
s_i和s_j
si和sj换后本质不同,
则
s
i
与
s
j
s_i与s_j
si与sj一定不是回文串,但为了不重复,我们找到第一个不同的交换,后面如果出现相同的就是同种方案
d p [ i ] 表 示 前 i 个 中 字 符 串 的 方 案 数 dp[i]表示前i个中字符串的方案数 dp[i]表示前i个中字符串的方案数
我们扫描前面有几个数和它不同就行了,不同的交换一定不是同种方案,而相同的在比 s i , s j s_i,s_j si,sj小的字符串的时候已经算过了,所以只要找到不同的个数即可
但不同的个数有点难求,所以我们只需要 找 出 相 同 的 个 数 减 去 不 同 的 个 数 即 可 \color{blue}找出相同的个数减去不同的个数即可 找出相同的个数减去不同的个数即可
——————————————————————————————————————————————
我们发现这道题是可以线性递推的。
即知道了前
i
i
i个的不同字符串一定能推出
i
+
1
i+1
i+1,我们统计出到i的字符总数和每个字母的个数就行了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100000010;
char s[N];
ll dp[N];
ll sum[26],summ;
int main(){
{
scanf("%s",s+1);
int n=strlen(s+1);
dp[1]=1,summ=1;
memset(sum,0,sizeof(sum));
sum[s[1]-'a']++;
for(int i=2;i<=n;i++){
dp[i]=dp[i-1];
dp[i]+=summ-sum[s[i]-'a'];
sum[s[i]-'a']++;
summ++;
}
printf("%lld\n",dp[n]);
}
}