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

(蛋糕真好吃呜呜呜)

这篇题解参考了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. 快速入门分布式消息队列之 RabbitMQ(2)

    目录 目录 前文列表 RabbitMQ 的特性 Message Acknowledgment 消息应答 Prefetch Count 预取数 RPC 远程过程调用 vhost 虚拟主机 插件系统 最后 ...

  2. 在性能测试时使用nmon进行监控服务器性能

    在使用Jmeter进行性能测试,可以使用nmon进行服务器的监控. 一.nmon说明 nmon分为工具包和分析包(nmonanalyser) nmon安装很简单,根据服务器版本,下载相应的版本后,进行 ...

  3. 编写shell脚本一键启动 重启 停止springboot项目

    #!/bin/bash #设置环境变量 export JAVA_HOME=/usr/local/jdk1.8.0_181 export JRE_HOME=/$JAVA_HOME/jre export ...

  4. PHP 数组函数 内部指针

    current( &$arr ) 每个数组的当前单元,初始值的 数组的第一个单元next ( &$arr ) 返回数组中的下一个单元 , 如果没值则返回falshprev ( & ...

  5. kafka学习(七)

    跨集群数据镜像 跨集群镜像的使用场景 1.区域集群和中心集群 2.冗余,发生紧急情况下使用第二个集群,保存相同的数据. 3.云迁移   多集群架构   跨集群中心通信的一些现实情况 1.高延迟 2.有 ...

  6. 初识HTML标签

    web概念概述 JavaWeb: 使用Java语言开发基于互联网的项目 软件架构: C/S: Client/Server 客户端/服务器端 在用户本地有一个客户端程序,在远程有一个服务器端程序 如:Q ...

  7. 自动构建War包的Ant build.xml模板

    <?xml version="1.0" encoding="UTF-8" ?> <project name="[*****]你的项目 ...

  8. SSIS包定时执行

    企业管理器 --管理 --SQL Server代理 --右键作业 --新建作业 --"常规"项中输入作业名称 --"步骤"项 --新建 --"步骤名& ...

  9. P1056排坐椅

    这是2008普及组真题,是一个提高—的模拟. 仔细读完题便有了思路:累放在i行能隔开wi个,比较排序wi,输出即可.所以在这里遇到了结构体排序的问题与手写cmp的问题.对于两个语法知识掌握得都不好,所 ...

  10. 小白学Python——用 百度翻译API 实现 翻译功能

    本人英语不好,很多词组不认识,只能借助工具:百度翻译和谷歌翻译都不错,近期自学Python,就想能否自己设计一个百度翻译软件呢? 百度翻译开放平台: http://api.fanyi.baidu.co ...