传送门


豪华升级版同余类最短路……

官方题解

主要写几个小trick:

\(1.O(nm)\)实现同余类最短路:

设某一条边长度为\(x\),那么我们选择一个点,在同余类上不断跳\(x\),可以形成一个环。

显然只有在同一个环上的两点之间才可能通过\(x\)进行转移。我们选择环上答案最小的点,它一定不会在当次更新时被更新答案,所以直接从这个点开始依次遍历环上的所有点,每一个点尝试从前面的一个点更新答案。

\(2.\)将\(\mod n\)的同余类最短路变为\(\mod d\)的同余类最短路:

令新的同余类最短路为\(g_x\),原同余类最短路为\(f_x\),那么首先令\(g_{f_i \mod d} \leftarrow f_i\),但是可能会有一些\(g\)没有被正确更新。在\(f_x\)中实际上还有默认的长度为\(n\)的边,那么在\(g\)中用长度为\(n\)的边在\(g\)上更新一次同余类最短路就可以得到正确的答案了。

\(3.\)更新\(border\)长度为等差数列的一段数的操作过程:

设这一个等差数列的首项为\(x\),公差为\(y\),有\(t+1\)项,先将原最短路变为\(\mod x\)的同余类最短路,那么对于每一个环上的点,可以从前面\(t\)个点进行转移,代价为距离\(\times y + x\),本质是一个多重背包。与此同时类似trick1地,转移一定不会跨越一个环上的最小值点,所以可以破环成链变为多重背包问题,使用单调队列优化转移。

PS:UOJ EX5好毒瘤啊……

Update on 2019.12.28:重写了一遍终于过了UOJ的Ex test,特来还愿。下面的代码更新为可以通过UOJ的代码。

#include<bits/stdc++.h>
using namespace std; #define ll long long
const int _ = 5e5 + 7;
char str[_]; ll mn[_] , tmp[_] , W; int T , L , curl , nxt[_];
template < typename T >
void chkmin(T &a , T b){a = a < b ? a : b;}
int upd(int x){return x + (x >> 31 & curl);} int num[_];
void ext(int len){
int stp = len % curl; if(!stp) return;
memset(num , 0 , sizeof(int) * (curl + 1));
for(int i = 0 ; !num[i] ; ++i){
int x = i , id = i;
do{id = mn[id] > mn[x] ? x : id; x = upd(x + stp - curl); num[x] = 1;}while(x != i);
x = id; do{int p = upd(x + stp - curl); chkmin(mn[p] , mn[x] + len); x = p;}while(x != id);
}
} ll val[_]; int que[_] , hd , tl;
void ext1(int len , int tms){
int stp = len % curl; if(!stp) return;
memset(num , 0 , sizeof(int) * (curl + 1));
for(int i = 0 ; !num[i] ; ++i){
int x = i , id = i , cnt = 0;
do{id = mn[id] > mn[x] ? x : id; x = upd(x + stp - curl);}while(x != i);
x = id; hd = tl = 0;
do{
num[x] = ++cnt; if(hd != tl && cnt - num[que[hd]] > tms) ++hd;
if(hd != tl) chkmin(mn[x] , val[que[hd]] + 1ll * stp * cnt + curl);
val[x] = mn[x] - 1ll * stp * cnt;
while(hd != tl && val[que[tl - 1]] >= val[x]) --tl;
que[tl++] = x; x = upd(x + stp - curl);
}while(x != id);
}
} void change(int nl){
memset(tmp , 0x3f , sizeof(ll) * max(tl , nl));
for(int i = 0 ; i < curl ; ++i) chkmin(tmp[mn[i] % nl] , mn[i]);
int tl = curl; curl = nl; memcpy(mn , tmp , sizeof(ll) * max(tl , nl)); ext(tl);
} int main(){
nxt[0] = -1;
for(scanf("%d" , &T) ; T ; --T){
scanf("%d %lld %s" , &L , &W , str + 1); W -= L;
memset(mn , 0x3f , sizeof(mn)); mn[0] = 0;
for(int i = 1 ; i <= L ; ++i){
int t = nxt[i - 1];
while(~t && str[t + 1] != str[i]) t = nxt[t];
nxt[i] = t + 1;
}
vector < int > border; int t = curl = L , pos = 0;
while(nxt[t]) border.push_back(L - (t = nxt[t]));
while(pos < border.size())
if(pos + 2 >= border.size()) ext(border[pos++]);
else if(border[pos + 2] - border[pos + 1] == border[pos + 1] - border[pos]){
int r = pos + 2 , len = border[pos + 1] - border[pos];
while(r + 1 < border.size() && border[r + 1] - border[r] == len) ++r;
change(border[pos]); ext1(len , r - pos); pos = r + 1;
}
else ext(border[pos++]);
ll sum = 0;
for(int i = 0 ; i < curl ; ++i)
if(W >= mn[i]) sum += (W - mn[i]) / curl + 1;
cout << sum << endl;
}
return 0;
}

Luogu4156 WC2016 论战捆竹竿 KMP、同余类最短路、背包、单调队列的更多相关文章

  1. luogu P4156 [WC2016]论战捆竹竿

    传送门 官方题解(证明都在这) 神仙题鸭qwq 转化模型,发现这题本质就是一个集合,每次可以加上集合里的数,问可以拼出多少不同的数 首先暴力需要膜意义下的最短路,例题戳这 然后这个暴力可以优化成N^2 ...

  2. bzoj4406: [Wc2016]论战捆竹竿&&uoj#172. 【WC2016】论战捆竹竿

    第二次在bzoj跑进前十竟然是因为在UOJ卡常致死 首先这个题其实就是一个无限背包 一般做法是同余最短路,就是bzoj2118: 墨墨的等式可以拿到30分的好成绩 背包是个卷积就分治FFT优化那么下面 ...

  3. BZOJ4406 WC2016 论战捆竹竿

    Problem BZOJ Solution 显然是一个同余系最短路问题,转移方案就是所有|S|-border的长度,有 \(O(n)\) 种,暴力跑dijkstra的复杂度为 \(O(n^2\log ...

  4. 「WC2016」论战捆竹竿

    「WC2016」论战捆竹竿 前置知识 参考资料:<论战捆竹竿解题报告-王鉴浩>,<字符串算法选讲-金策>. Border&Period 若前缀 \(pre(s,x)​\ ...

  5. UOJ#172. 【WC2016】论战捆竹竿

    传送门 首先这个题目显然就是先求出所有的 \(border\),问题转化成一个可行性背包的问题 一个方法就是同余类最短路,裸跑 \(30\) 分,加优化 \(50\) 分 首先有个性质 \(borde ...

  6. 【LuoguP4156】论战捆竹竿

    题目链接 题意简述 你有一个长度为 n 的字符串 , 将它复制任意次 , 复制出的串的前缀可以与之前的串的后缀重叠在一起 , 问最后总共可能的长度数目 , 长度不能超过 \(w\) 多组数据. \(n ...

  7. BZOJ2118 墨墨的等式[同余类最短路]

    声明:关于这题的$O(mn)$尚且未深入理解,虽然之前有跟这位神仙聊过做法但并没太懂.. $O(mn\log m)$同余最短路做法: 首先不妨抽出最小的$a_i=m$,那么剩余的$a$如果可以表示出$ ...

  8. 【WC2016】论战捆竹竿

    已经快三周了啊--终于把挖的坑填了-- 首先显然是把除了自身的所有border拿出来,即做 \(\left\{ n - b_1, n - b_2, \dots, n - b_k, n \right\} ...

  9. UOJ#172. 【WC2016】论战捆竹竿 字符串 KMP 动态规划 单调队列 背包

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ172.html 题解 首先,这个问题显然是个背包问题. 然后,可以证明:一个字符串的 border 长度可 ...

随机推荐

  1. 两年AI研究经验(教训)总结,进来看看吧!

    https://www.jianshu.com/p/2149c9fee166 摘要: 本文以过来人的身份将自身2年的研究经验做了一下分享,希望本文对于即将开始从事人工智能研究的朋友有所帮助. 人工智能 ...

  2. angularjs的$http请求方式

    /*$http常用的几个参数 $http服务的设置对象: 1.method 字符串 表示发送的请求类型 get post jsonp等等 2.url 字符串 绝对或者相对的URL,请求的目标 3.pa ...

  3. flask中的url_for的使用

    有多个路由的程序需要连接不同的网页链接,例如导航条 模板中构建正确的动态url较为困难,如果重定义路由,模板中的链接失效 url_for()函数: 使用url映射中保存的信息生成url 用法: 用视图 ...

  4. LeetCode题解之Balanced Binary Tree

    1.题目描述 2.问题分析 DFS. 3.代码 bool isBalanced(TreeNode* root) { if (root == NULL) return true; && ...

  5. maven五:查找jar包坐标,选择jar包版本

    查找jar包坐标 以spring core的jar包为例,访问http://www.mvnrepository.com/    在最上方中间,输入spring core,点击Search. 搜索结果第 ...

  6. js实现页面锚点定位动画滚动

    项目上需要的效果,个人不想用jquery实现,想着用js自己试试,花了点儿时间,终于实现.. 上干货.. function scrollTo(y, duration) { /*y:目标纵坐标,dura ...

  7. python第二十九天-----继续学习第三模块——前几天旅行去了

    subprocess模块 import subprocess subprocess.getstatusoutput('dir')#接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结 ...

  8. Spring boot + mybatis + orcale

    接着上次的实现, 添加 mybatis 查询 orcale 数据库 第一步: 新建几个必须的包, 结果如下 第二步: 在service包下新建personService.java 根据名字查perso ...

  9. Java设计模式之五 ----- 外观模式和装饰器模式

    前言 在上一篇中我们学习了结构型模式的适配器模式和桥接模式.本篇则来学习下结构型模式的外观模式和装饰器模式. 外观模式 简介 外观模式隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.这 ...

  10. 新鲜出炉的jquery fileupload 插件

    内容属原创,转载请注明出处 为什么做这个东东 项目中需要用到一个多附件上传的控件,找了一圈没找到中意的(唯一一个中意点的还不开源,费用比较高),这不,只得自己抡刀上了. 需求是什么 这么个上传的东东, ...