2018 焦作网络赛 L Poor God Water ( AC自动机构造矩阵、BM求线性递推、手动构造矩阵、矩阵快速幂 )
题意 :
实际上可以转化一下题意
要求求出用三个不同元素的字符集例如 { 'A' 、'B' 、'C' }
构造出长度为 n 且不包含
AAA、BBB
CCC、ACB
BCA、CAC
CBC
这其中任意一个字符串的方案数
分析 :
方法一 (BM 求线性递推)
直接暴力出前 10 项的答案、然后猜它其实可以由线性递推递推而来
丢进杜教的 BM 模板里面就可以直接求出第 N 项了
实际上这个可以不用猜、这种不包含某些串的题目
如果你做过类似的、就会知道实际上是可以构造出一个矩阵然后快速幂
可以使用矩阵快速幂优化的递推方程大概都可以用 BM 求
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <cassert>
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
;
ll powmod(ll a,ll b) {ll res=;a%=mod; assert(b>=); ){)res=res*a%mod;a=a*a%mod;}return res;}
// head
ll n;
namespace linear_seq {
;
ll res[N],base[N],_c[N],_md[N];
vector<int> Md;
void mul(ll *a,ll *b,int k) {
rep(i,,k+k) _c[i]=;
rep(i,,k) ,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
;i>=k;i--) if (_c[i])
rep(j,,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
rep(i,,k) a[i]=_c[i];
}
int solve(ll n,VI a,VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
ll ans=,pnt=;
int k=SZ(a);
assert(SZ(a)==SZ(b));
rep(i,,k) _md[k--i]=-a[i];_md[k]=;
Md.clear();
rep(i,,k) ) Md.push_back(i);
rep(i,,k) res[i]=;
res[]=;
while ((1ll<<pnt)<=n) pnt++;
;p--) {
mul(res,res,k);
) {
;i>=;i--) res[i+]=res[i];res[]=;
rep(j,,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
}
}
rep(i,,k) ans=(ans+res[i]*b[i])%mod;
) ans+=mod;
return ans;
}
VI BM(VI s) {
VI C(,),B(,);
,m=,b=;
rep(n,,SZ(s)) {
ll d=;
rep(i,,L+) d=(d+(ll)C[i]*s[n-i])%mod;
) ++m;
*L<=n) {
VI T=C;
ll c=mod-d*powmod(b,mod-)%mod;
);
rep(i,,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
L=n+-L; B=T; b=d; m=;
} else {
ll c=mod-d*powmod(b,mod-)%mod;
);
rep(i,,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
++m;
}
}
return C;
}
int gao(VI a,ll n) {
VI c=BM(a);
c.erase(c.begin());
rep(i,,SZ(c)) c[i]=(mod-c[i])%mod;
return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
}
};
int main() {
vector<int>v;
v.push_back();
v.push_back();
v.push_back();
v.push_back();
v.push_back();
v.push_back();
v.push_back();
v.push_back();
v.push_back();
v.push_back();
int nCase;
scanf("%d", &nCase);
while(nCase--){
scanf("%lld", &n);
printf() % mod);
}
}
方法二 (AC自动机构造矩阵 + 矩阵快速幂)
如果你做过 POJ 2778 那么你就能够知道这个题目
实际上将不合法的字符串丢到 AC 自动机里面去就可以构造出矩阵了
然后进行快乐的矩阵快速幂就阔以了
下面代码并非 AC 代码、只是使用 AC 自动机构造矩阵的代码
且代码大部分都使用了我写过的 POJ 2778 的代码、输入形式可看代码最后注释
#include<queue>
#include<stdio.h>
#include<string.h>
using namespace std;
;
;
;
int maxn;
];
][]; }unit, M;
mat operator * (mat a, mat b)
{
mat ret;
long long x;
; i<maxn; i++){
; j<maxn; j++){
x = ;
; k<maxn; k++){
x = (x + ((long long)a.m[i][k]%MOD * b.m[k][j]%MOD)%MOD)%MOD;
}
ret.m[i][j] = x % MOD;
}
}
return ret;
}
inline ; i<maxn; i++) unit.m[i][i] = ; }
mat pow_mat(mat a, int n)
{
mat ret = unit;
while(n){
) ret = ret * a;
a = a*a;
n >>= ;
}
return ret;
}
struct Aho{
struct StateTable{
int Next[Letter];
int fail, flag;
}Node[Max_Tot];
int Size;
queue<int> que;
inline void init(){
while(!que.empty()) que.pop();
memset(Node[].Next, , ].Next));
Node[].fail = Node[].flag = ;
Size = ;
}
inline void insert(char *s){
;
; s[i]; i++){
int idx = mp[s[i]];
if(!Node[now].Next[idx]){
memset(Node[Size].Next, , sizeof(Node[Size].Next));
Node[Size].fail = Node[Size].flag = ;
Node[now].Next[idx] = Size++;
}
now = Node[now].Next[idx];
}
Node[now].flag = ;
}
inline void BuildFail(){
Node[].fail = ;
que.push();
while(!que.empty()){
int top = que.front(); que.pop();
;///如果当前节点的Fail指针指向的节点也是末尾节点,那么这个节点也是不合法的!
; i<Letter; i++){
if(Node[top].Next[i]){
) Node[ Node[top].Next[i] ].fail = ;
else{
int v = Node[top].fail;
){
if(Node[v].Next[i]){
Node[ Node[top].Next[i] ].fail = Node[v].Next[i];
break;
}v = Node[v].fail;
}) Node[ Node[top].Next[i] ].fail = ;
}que.push(Node[top].Next[i]);
}?Node[ Node[top].fail ].Next[i]:;///多了这一句!
}
}
}
inline void BuildMatrix(){
; i<Size; i++)
; j<Size; j++)
M.m[i][j] = ;
; i<Size; i++){
; j<Letter; j++){
if(!Node[i].flag && !Node[ Node[i].Next[j] ].flag)
M.m[i][Node[i].Next[j]]++;
}
}
maxn = Size;
}
}ac;
];
int main(void)
{
mp[,
mp[,
mp[;
int n, m;
while(~scanf("%d %d", &m, &n)){
ac.init();
; i<m; i++){
scanf("%s", S);
ac.insert(S);
}
ac.BuildFail();
ac.BuildMatrix();
; i<; i++){
; j<; j++){
printf("%d ", M.m[i][j]);
}puts("");
}puts("");
init_unit();
M = pow_mat(M, n);
// for(int i=0; i<10; i++){
// for(int j=0; j<10; j++){
// printf("%d ", M.m[i][j]);
// }puts("");
// }puts("");
;
; i<ac.Size; i++)
ans = (ans + M.m[][i])%MOD;
ans %= MOD;
printf("%d\n", ans);
}
;
}
/*输入 7 和 n 然后输入字符集、就能出答案*/
/**
7 15
AAA
BBB
CCC
ACB
BCA
CAC
CBC
*/
方法三 (手动构造矩阵 + 矩阵快速幂)
首先使用各种手段抓一个聪明伶俐的队友过来
此队友需要在矩阵构造方面颇有灵性
把题目交给他翻译、构思、打代码
等待 15 分钟左右、最后即可得到 Accept
2018 焦作网络赛 L Poor God Water ( AC自动机构造矩阵、BM求线性递推、手动构造矩阵、矩阵快速幂 )的更多相关文章
- ACM-ICPC 2018 焦作网络赛
题目顺序:A F G H I K L 做题链接 A. Magic Mirror 题意:判断 给出的 字符串 是否等于"jessie",需要判断大小写 题解:1.用stl库 tolo ...
- ACM-ICPC 2018 焦作赛区网络预赛 L Poor God Water(矩阵快速幂,BM)
https://nanti.jisuanke.com/t/31721 题意 有肉,鱼,巧克力三种食物,有几种禁忌,对于连续的三个食物:1.这三个食物不能都相同:2.若三种食物都有的情况,巧克力不能在中 ...
- 2018 焦作网络赛 G Give Candies ( 欧拉降幂 )
题目链接 题意 : 给出 N 个糖果.老师按顺序给 1~N 编号的学生分配糖果.每个学生要么不分.要么最少分一个.且由于是按顺序发放.那么对于某个有分到糖果的编号为 i 的学生.则 1~(i-1) 这 ...
- 2018焦作网络赛 - Poor God Water 一道水题的教训
本题算是签到题,但由于赛中花费了过多的时间去滴吧格,造成了不必要的浪费以及智商掉线,所以有必要记录一下坑点 题意:方格从1到n,每一格mjl可以选择吃鱼/巧克力/鸡腿,求走到n格时满足 1.每三格不可 ...
- 2018 焦作网络赛 K Transport Ship ( 二进制优化 01 背包 )
题目链接 题意 : 给出若干个物品的数量和单个的重量.问你能不能刚好组成总重 S 分析 : 由于物品过多.想到二进制优化 其实这篇博客就是存个二进制优化的写法 关于二进制优化的详情.百度一下有更多资料 ...
- 2018焦作网络赛-E- Jiu Yuan Wants to Eat
题目描述 You ye Jiu yuan is the daughter of the Great GOD Emancipator. And when she becomes an adult, s ...
- 2018焦作网络赛Mathematical Curse
题意:开始有个数k,有个数组和几个运算符.遍历数组的过程中花费一个运算符和数组当前元素运算.运算符必须按顺序花费,并且最后要花费完.问得到最大结果. 用maxv[x][y]记录到第x个元素,用完了第y ...
- 2018焦作网络赛Give Candies
一开始忽略了欧拉定理指数部分是modphi(n-1)没有memset,减法后面没加0:
- 2018南京网络赛L题:Magical Girl Haze(最短路分层图)
题目链接:https://nanti.jisuanke.com/t/31001 解题心得: 一个BZOJ的原题,之前就写过博客了. 原题地址:https://www.lydsy.com/JudgeOn ...
随机推荐
- Linux的桌面环境gnome、kde、xfce、lxde 等等使用比较
如果不是加入了图形界面,微软的Windows系列操作系统不会成功地占领计算机桌面这块高地.这种人机交换的图形化界面,使得界面更加直观.简易.而且更人性化,同时也大大减少了使用者的认知负担,普通用户无需 ...
- JavaRMI框架
RMI(即Remote Method Invoke 远程方法调用).在Java中,只要一个类extends了java.rmi.Remote接口,即可成为存在于服务器端的远程对象,供客户端访问并提供一 ...
- php设计模式之注册模式
注册模式,解决全局共享和交换对象.已经创建好的对象,挂在到某个全局可以使用的数组上,在需要使用的时候,直接从该数组上获取即可.将对象注册到全局的树上.任何地方直接去访问. <?php class ...
- Python 入门 之 类成员
Python 入门 之 类成员 1.类的私有成员: 私有: 只能自己拥有 以 __ 开头就是私有内容 对于每一个类的成员而言都有两种形式: - 公有成员,在任何地方都能访问 - 私有成员,只有在类的内 ...
- 如何将本地的项目推送至git仓库
转载:https://www.jianshu.com/p/31dea20b0084 1.cd projectName probjectName是项目文件夹的名字, 先进入项目文件夹 2.git ini ...
- Codeforces 1228C. Primes and Multiplication
传送门 当然是考虑 $n$ 的每个质数 $p$ 对答案的贡献 考虑 $p^k$ 在 $[1,m]$ 中出现了几次,显然是 $\left \lfloor \frac{m}{p^k} \right \rf ...
- 面试常考的js题目(一)
1.找出dom文档中某个元素下面的所有文字(面试写的一塌糊涂,回来重写的) 1.返回回数组形式的 function getText(ele) { if (ele.nodeType === 3) { r ...
- vscode 格式化vue代码单引号变双引号
首选项->设置.输入框输入vetur vscode中设置 "vetur.format.defaultFormatterOptions": { "prettier&q ...
- Vue项目里添加特殊字体或 某些字体乱码的问题
问题:有个西藏的项目因使用藏文,而出现乱码 (一开始不乱的,不知道后台怎么处理...后来不知道为啥,前端乱码了) 解决:字体ttf 格式已下载,在项目中全局引入了 @font-face { font- ...
- 51. N-Queens (JAVA)
The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens ...