这道题神仙到让我面临着买不到冰皮月亮蛋糕的风险来写题解

(蛋糕真好吃呜呜呜)

这篇题解参考了CQzhangyu神仙的做法。

(目测比标程科学好写)

限制是要回文,根据我们做字符串计数的常识,一定是尽量能匹配的先匹配上,这样就不会重复计数了。

因此,可以想到一种直观的DP方法:

令$f[i][j][k]$表示前面匹配到i后面匹配到j加入了k个字符的方案数,我们每次看它是否和前后匹配来转移。

那么它应该是一个有限状态自动机上的转移 大概长这个样子

相当于有向图上路径计数,于是就可以矩乘优化。考虑它有S^3个节点,肯定没戏的。

进一步优化

我们把前后不同的转移标记为红点 它有方案数为24的自环,相同类似的标为绿点。

那么我们发现我们其实并不关心红绿的顺序,我们只关心它出现的次数,最后乘上方案数就可以了。

先考虑我们如何得到这个方案数,用$f[i][j][k]$表示前i个和后j个,走过k个红点的方案数。

有两种转移

1.ch[i]==ch[j]

$f[i+1][j-1][k] += f[i][j][k]$

2.ch[i]!=ch[j]

$f[i+1][j][k]+=f[i][j][k]$

$f[i][j-1][k]+=f[i][j][k]$

我们现在再来看看原来的自动机变成了什么样子

应该是这个样子,每一条链有x个红点 $\lceil \frac{n-x}{2} \rceil$个绿点

如果我们再把它们合并到一张图中,应该长这个样子了

(盗CQzhangyu神仙的图)

我们把方案数直接放到红点与绿点之间的边上。

那么我们就有了一个很科学的解法了,我们现在再在这个图上跑矩乘就ok了。

等等,奇数好像不大对?

我们发现奇数的时候匹配ch[i]和ch[i+1]以后不能直接随便填的转移,它们分别位于中间的两边并且中间的元素填的跟它们一样的时候我们算重了1次,所以方案数多了。

那么我们重新再做一遍类似的矩乘就可以了,现在红点绿点之间的边是强制$ch[i]==ch[i+1]$的方案数。

最后终点还要去掉自环,这样我们的方案数就算对了。

接着你发现你T了!

可以发现我们是个DAG所以按照拓扑序转移可以顺序枚举点,这样加上一个1/6常数就能跑过了qwq

我觉得此题过于神仙QAQ

当然还有更神仙的解法来自cz_xuyixuan巨佬

(讲真我看到这个做法直接惊呆了= =)

还有官方题解的做法,其实就是不缩点而已,个人认为CQzhangyu神仙的解法更为简便。

附代码。

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 20021225
#define mdn 10007
#define N 310
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return f*s;
}
struct mat
{
int a[N][N],n;
void init(){memset(a,,sizeof(a));}
void det(){init(); for(int i=;i<=n;i++) a[i][i]=;}
}s,t;
mat operator*(mat a,mat b) // 1/6!
{
mat tmp; tmp.n=a.n; tmp.init();
for(int i=;i<=a.n;i++) for(int j=i;j<=a.n;j++)
for(int k=i;k<=j;k++) tmp.a[i][j]=(tmp.a[i][j]+a.a[i][k]*b.a[k][j])%mdn;
return tmp;
}
mat ksm(mat bs,int mi,mat &ans)
{
while(mi)
{
if(mi&) ans=ans*bs;
bs=bs*bs; mi>>=;
}
return ans;
}
int f[][][],g[];
char ch[N]; int n,d;
void upd(int &x,int y){x+=x+y>=mdn?y-mdn:y;}
void dp()
{
f[][n][]=;
for(int i=;i<=n;i++) for(int j=n;j>=i;j--)
if(ch[i]==ch[j]) for(int k=;k<i+n-j;k++)
if(i+<j) upd(f[i+][j-][k],f[i][j][k]);
else upd(g[k],f[i][j][k]);
else for(int k=;k<i+n-j;k++)
upd(f[i+][j][k+],f[i][j][k]),
upd(f[i][j-][k+],f[i][j][k]);
}
int main()
{
scanf("%s",ch+); n=strlen(ch+); d=read(); dp();
int top=n+(n+)/+; s.n=t.n=top; s.a[][]=;
s.a[][top-(n+)/]=g[]; t.a[top][top]=;
for(int i=;i<=n;i++)
{
t.a[i][i]=,t.a[i][top-(n-i+)/]=g[i];
if(i!=n) t.a[i][i+]=;
}
for(int i=n+;i<top;i++) t.a[i][i+]=,t.a[i][i]=;
if((n+d)&)
{
ksm(t,d+n+>>,s);
int ans=s.a[][top];
s.init(); t.init(); memset(g,,sizeof(g));
for(int i=;i<n;i++) if(ch[i]==ch[i+])
for(int j=;j<=n;j++) upd(g[j],f[i][i+][j]);
s.a[][]=; s.a[][top-(n+)/]=g[];
for(int i=;i<=n;i++)
{
t.a[i][i]=,t.a[i][top-(n-i+)/]=g[i];
if(i!=n) t.a[i][i+]=;
}
for(int i=n+;i<top;i++) t.a[i][i+]=,t.a[i][i]=;
ksm(t,d+n+>>,s); printf("%d\n",(ans-s.a[][top]+mdn)%mdn);
}
else
ksm(t,d+n>>,s),printf("%d\n",s.a[][top]);
return ;
}

CF506E Mr. Kitayuta's Gift的更多相关文章

  1. 【CF506E】Mr. Kitayuta's Gift dp转有限状态自动机+矩阵乘法

    [CF506E]Mr. Kitayuta's Gift 题意:给你一个字符串s,你需要在s中插入n个字符(小写字母),每个字符可以被插在任意位置.问可以得到多少种本质不同的字符串,使得这个串是回文的. ...

  2. Codeforces 505A Mr. Kitayuta's Gift 暴力

    A. Mr. Kitayuta's Gift time limit per test 1 second memory limit per test 256 megabytes input standa ...

  3. 水题 Codeforces Round #286 (Div. 2) A Mr. Kitayuta's Gift

    题目传送门 /* 水题:vector容器实现插入操作,暴力进行判断是否为回文串 */ #include <cstdio> #include <iostream> #includ ...

  4. codeforces Round 286# problem A. Mr. Kitayuta's Gift

    Mr. Kitayuta has kindly given you a string s consisting of lowercase English letters. You are asked ...

  5. codeforces 505A. Mr. Kitayuta's Gift 解题报告

    题目链接:http://codeforces.com/problemset/problem/505/A 题目意思:给出一个长度不大于10的小写英文字符串 s,问是否能通过在字符串的某个位置插入一个字母 ...

  6. Codeforces 505 A Mr. Kitayuta's Gift【暴力】

    题意:给出一个字符串,可以向该字符串的任意位置插入一个字母使其变成回文串 因为字符串的长度小于10,枚举插入的字母,和要插入的位置,再判断是否已经满足回文串 #include<iostream& ...

  7. Codeforces 506E Mr. Kitayuta's Gift (矩阵乘法,动态规划)

    描述: 给出一个单词,在单词中插入若干字符使其为回文串,求回文串的个数(|s|<=200,n<=10^9) 这道题超神奇,不可多得的一道好题 首先可以搞出一个dp[l][r][i]表示回文 ...

  8. 【Codeforces 506E】Mr.Kitayuta’s Gift&&【BZOJ 4214】黄昏下的礼物 dp转有限状态自动机+矩阵乘法优化

    神题……胡乱讲述一下思维过程……首先,读懂题.然后,转化问题为构造一个长度为|T|+n的字符串,使其内含有T这个子序列.之后,想到一个简单的dp.由于是回文串,我们就增量构造半个回文串,设f(i,j, ...

  9. Codeforces Round #286 (Div. 2)A. Mr. Kitayuta's Gift(暴力,string的应用)

    由于字符串的长度很短,所以就暴力枚举每一个空每一个字母,出现行的就输出.这么简单的思路我居然没想到,临场想了很多,以为有什么技巧,越想越迷...是思维方式有问题,遇到问题先分析最简单粗暴的办法,然后一 ...

随机推荐

  1. nginx请求转发配置

    以下为无ssl证书配置的请求转发 server { listen ; server_name api.****.com; #以下为指定请求域名匹配到某一个端口 #location ~* /union ...

  2. cannot assign to struct field xxx in map

    golang 中对 map 类型中的 struct 赋值报错 type s struct{ name string age int}func main(){ a := map[string]s{ &q ...

  3. 【HANA系列】SAP HANA SQL获取本周的周一

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA SQL获取本周 ...

  4. cocos2dx基础篇(10) 按钮控件CCControlButton

    [3.x] (1)去掉 “CC” (2)对象类 CCObject 改为 Ref (3)按钮事件回调依旧为 cccontrol_selector ,没有使用 CC_CALLBACK_2 (4)按钮状态  ...

  5. 基于html5二个div 连线

    因为要实现拖拽连线研究了一下基于extjs 和html5的不同实现方法 extjs底层的画图引擎是svg 不知道在html5大潮即将袭来的前夕一贯走在技术前沿的extjs开发团队没有自己封装基于htm ...

  6. 【Python基础】_2 Python基本语法与常识(迭代优化中...)

    2 Python的基本语法 为了保证Python解释器能顺利编译所编写的代码,也为了程序员对自己和别人所编写的程序易于阅读.维护,对编程语言的语法做一些基本约定是非常必要的. 2.1 编程方式 2.1 ...

  7. 转:mysql datetime类型精确到毫秒、微秒的问题

    原文地址:mysql datetime类型精确到毫秒.微秒的问题 mysql里面的datetime类型的精确度是可以到1/ 10 ^ 6 秒的某些客户端(如navicat for mysql)的显示经 ...

  8. [LeetCode] 212. 单词搜索 II

    题目链接:https://leetcode-cn.com/problems/word-search-ii/ 题目描述: 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在 ...

  9. [LeetCode] 84. 柱状图中最大的矩形

    题目链接 : https://leetcode-cn.com/problems/largest-rectangle-in-histogram/ 题目描述: 给定 n 个非负整数,用来表示柱状图中各个柱 ...

  10. RouteReuseStrategy angular路由复用策略详解,深度刨析路由复用策略

    关于前端路由复用策略网上的文章很多,大多是讲如何实现tab标签切换历史数据,至于如何复用的原理讲的都比较朦胧,代码样例也很难适用各种各样的路由配置,比如懒加载模式下多级嵌套路由出口网上的大部分代码都会 ...