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

(蛋糕真好吃呜呜呜)

这篇题解参考了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. GO开发:etcd用法

    etcd是什么? A highly-available key value store for shared configuration and service discovery.是一个键值存储仓库 ...

  2. lua源码学习篇二:语法分析

    一步步调试,在lparser.c文件中luaY_parser函数是语法分析的重点函数,词法分析也是在这个过程中调用的.在这个过程中,用到一些数据结构,下面会详细说. Proto *luaY_parse ...

  3. 你知道 Git 是如何做版本控制的吗?(转)

    总结:阅读这篇文章需要20分钟 本文是转载自 滴滴WebApp架构组 的一篇文章,文章讲解了神秘的.git目录下的一些文件,最终阐述了git是如何存储数据,及git分支的相关内容. git如何存储数据 ...

  4. webService框架CXF的简单使用

    最近本来已经将上一个项目交活,全身心投入了另外项目的前端的开发工作.可之前的项目经理通知我,之前的项目需要做一个webService的功能,于是稍微做了一下webService,可是忘了通知我现在的项 ...

  5. sql语句小记录

    测试过程中,需要去数据库中查询一些结果,比如验证码 常用的是查询 更新比较少用 删除一般不用 sql查询语句的嵌套用法,比较实用 比如in的用法:第一种:查询多个值时 SELECT "栏位名 ...

  6. lua正则表达式替换字符串

    local _t = {} _t.name = "Li" local str = string.gsub("hahah---[name]----[age]--xrz-&q ...

  7. vim加脚本注释和文本加密

    vim /etc/vimrc 一.李导版本 autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()" fun ...

  8. ubuntu 环境配置

    安装包准备 下载 410以上显卡驱动 文件名: NVIDIA-Linux-x86_64-410.66.run 下载 cuda 10.0 选择 CUDA Toolkit 10.0 (Sept 2018) ...

  9. Linux 后台执行python或者java代码的命令

    1.nohup 命令操作后台执行程序 后台启动 nohup python app.py params1 > nohup.out >& & 查看后台进程启动 jobs -l ...

  10. netstat -anop|more 查看网络队列

    nux下netstat --timers / -o详解及keepalive相关 第一列,一般有一下几种状态: keepalive - #表示是keepalive的时间计时 on - #表示是重发(re ...