Codeforces 917C - Pollywog(状压 dp+矩阵优化)
UPD 2021.4.9:修了个 typo,为啥写题解老出现 typo 啊(
这是一道 *2900 的 D1C,不过还是被我想出来了
u1s1 大概是这题用到的几个套路我都见过罢
首先注意到 \(k\) 很小,故考虑状压 \(dp\),\(dp_{i,s}\) 表示当前所有 pollywog 都在编号 \([i-k+1,i]\) 范围内的石头上,并且有且仅有编号 \(i-x+1,x\in s\) 的石头上有 pollywog。
转移还是比较显然的,如果 \(k\in s\),那么我们必须强制让这个当前位于 \(i-k+1\) 位置的 pollywog 跳 \(k\) 步,否则我们可以枚举一个青蛙并让它跳到编号为 \(i+1\) 的石头上,或者干脆 \(i+1\) 位置上不放 pollywog,也就是说:
- \(dp_{i+1,s'}\leftarrow dp_{i,s}+c_k+a_{i+1},s'=\{x+1|x\in s\land x\ne k\}\cup\{1\}(k\in s)\)
- \(dp_{i+1,s'}\leftarrow dp_{i,s}+c_d+a_{i+1},s'=\{x+1|x\in s\land x\ne d\}\cup\{1\}(k\notin s,d\in s)\)
- \(dp_{i+1,s'}\leftarrow dp_{i,s}+c_k,s'=\{x+1|x\in s\}(k\notin s)\)
其中 \(c_i\) 为跳 \(i\) 格所需消耗的体力,\(a_i\) 为 \(i\) 所在的特殊格所额外消耗的体力(如果 \(i\) 不是特殊格则 \(a_i=0\))。
初始 \(dp_{x,\{1,2,\dots,x\}}=0\),答案为 \(dp_{n,\{1,2,\dots,x\}}\)。
考虑优化,注意到这个 \(n\) 很大但是这个转移呈规律性。故考虑矩阵优化 \(dp\),我们把转移方程用矩阵的形式表示出来,即我们总能找到一个矩阵 \(A\) 使得 \(A\times\begin{bmatrix}dp_{i,0}\\dp_{i,1}\\\dots\\dp_{i,2^k-1}\end{bmatrix}=\begin{bmatrix}dp_{i+1,0}\\dp_{i+1,1}\\\dots\\dp_{i+1,2^k-1}\end{bmatrix}\)(其中两个大小分别为 \(n\times m,m\times k\) 的矩阵 \(A,B\) 乘法得到的矩阵 \(C\) 为 \(n\times k\) 的矩阵,且 \(C_{i,j}=\min\limits_{l=1}^mA_{i,l}+B_{l,j}\))。那么如果没有什么特殊格子的限制的话,直接一遍矩阵快速幂就行了。
接下来考虑有特殊格子的情况,我们按照 CF576D 的套路将所有特殊格子按坐标排个序,显然一个特殊格子 \((x,y)\) 对 \(dp\) 值产生的影响就是令 \(\forall 1\in S,dp_{x,S}\leftarrow dp_{x,S}+y\)。故可以直接矩阵快速幂求出 \(dp_x\),然后就直接在 \(dp_x\) 上修改贡献即可。
这个算法的复杂度 \(\omega^3p\log n\) 的,其中 \(\omega=2^k\),无法通过。
考虑优化,注意到这个转移矩阵 \(A\) 是不会发生变化的,故考虑借鉴 P6772 的套路,而我们矩阵快速幂求出 \(dp_x\) 实质上是矩阵乘向量,单次乘法复杂度为 \(\omega^2\),故考虑预处理出 \(A^{2^k}\),这样可实现 \(\omega^3\log n\) 预处理,\(\omega^2p\log n\) 矩阵快速幂。
可是这样还是会炸啊……
这里还有第三个套路,就是对于合法的 \(dp_{i,S}\) 一定有 \(|S|=x\),故合法的状态最多 \(\binom{8}{4}=70\) 种,于是可以把所有合法的状态压缩成一个 \([1,70]\) 内的整数,这样矩阵大小就降到了 \(70\) 了。
时间复杂度 \(\omega^3\log n+\omega^2p\log n+\log p\),目前最优解 rk1
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXK=8;
const int MAXP=25;
const int MAX_SIZ=70;
const int LOG_N=28;
const ll INF=0x3f3f3f3f3f3f3f3fll;
int x,k,n,p,c[MAXK+2];pii t[MAXP+2];
int st[MAX_SIZ+5],st_n=0,id[1<<MAXK];
struct mat{
int n,m;ll a[MAX_SIZ+5][MAX_SIZ+5];
mat(){}
mat(int _n,int _m){
n=_n;m=_m;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
a[i][j]=INF;
}
mat operator *(const mat &rhs){
assert(m==rhs.n);mat res(n,rhs.m);
for(int i=1;i<=n;i++) for(int j=1;j<=rhs.m;j++)
for(int l=1;l<=m;l++) chkmin(res.a[i][j],a[i][l]+rhs.a[l][j]);
return res;
}
};
mat pw[LOG_N+2];
int main(){
scanf("%d%d%d%d",&x,&k,&n,&p);
for(int i=1;i<=k;i++) scanf("%d",&c[i]);
for(int i=1;i<=p;i++) scanf("%d%d",&t[i].fi,&t[i].se);
sort(t+1,t+p+1);
for(int i=0;i<(1<<k);i++) if(__builtin_popcount(i)==x){
st[++st_n]=i;id[i]=st_n;//printf("%d\n",i);
} mat trs(st_n,st_n);
for(int i=1;i<=st_n;i++){
if(st[i]>>(k-1)&1){
trs.a[id[((st[i]^(1<<(k-1)))<<1)|1]][i]=c[k];
} else {
for(int j=0;j<k;j++) if(st[i]>>j&1)
trs.a[id[((st[i]^(1<<j))<<1)|1]][i]=c[j+1];
trs.a[id[st[i]<<1]][i]=0;
}
}
// for(int i=1;i<=st_n;i++) for(int j=1;j<=st_n;j++)
// printf("%lld%c",trs.a[i][j],(j==st_n)?'\n':' ');
pw[0]=trs;
for(int i=1;i<=LOG_N;i++) pw[i]=pw[i-1]*pw[i-1];
int pre=x,init_msk=0;mat cur(st_n,1);
for(int i=0;i<x;i++) init_msk|=1<<i;
cur.a[id[init_msk]][1]=0;
for(int i=1;i<=p;i++){
int dif=t[i].fi-pre;
for(int j=LOG_N;~j;j--) if(dif>>j&1) cur=pw[j]*cur;
for(int j=1;j<=st_n;j++) if(st[j]&1) cur.a[j][1]+=t[i].se;
pre=t[i].fi;
}
int dif=n-pre;
for(int j=LOG_N;~j;j--) if(dif>>j&1) cur=pw[j]*cur;
printf("%lld\n",cur.a[id[init_msk]][1]);
// for(int i=1;i<=st_n;i++) printf("%d %lld\n",st[i],cur.a[i][1]);
return 0;
}
Codeforces 917C - Pollywog(状压 dp+矩阵优化)的更多相关文章
- BZOJ4000 [TJOI2015]棋盘 【状压dp + 矩阵优化】
题目链接 BZOJ4000 题解 注意题目中的编号均从\(0\)开始= = \(m\)特别小,考虑状压 设\(f[i][s]\)为第\(i\)行为\(s\)的方案数 每个棋子能攻击的只有本行,上一行, ...
- HDU 5434 Peace small elephant 状压dp+矩阵快速幂
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5434 Peace small elephant Accepts: 38 Submissions: ...
- 【BZOJ】2004: [Hnoi2010]Bus 公交线路 状压DP+矩阵快速幂
[题意]n个点等距排列在长度为n-1的直线上,初始点1~k都有一辆公车,每辆公车都需要一些停靠点,每个点至多只能被一辆公车停靠,且每辆公车相邻两个停靠点的距离至多为p,所有公车最后会停在n-k+1~n ...
- 【bzoj2004】[Hnoi2010]Bus 公交线路 状压dp+矩阵乘法
题目描述 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计 ...
- 【bzoj1097】[POI2007]旅游景点atr 状压dp+堆优化Dijkstra
题目描述 FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情.经过这些城市的顺序不是完全随意的,比如说FGD不希望在刚吃过一顿大餐之后立刻去下一个 ...
- 【XSY2524】唯一神 状压DP 矩阵快速幂 FFT
题目大意 给你一个网格,每个格子有概率是\(1\)或是\(0\).告诉你每个点是\(0\)的概率,求\(1\)的连通块个数\(\bmod d=0\)的概率. 最开始所有格子的概率相等.有\(q\)次修 ...
- 2018.09.28 hdu5434 Peace small elephant(状压dp+矩阵快速幂)
传送门 看到n的范围的时候吓了一跳,然后发现可以矩阵快速幂优化. 我们用类似于状压dp的方法构造(1(1(1<<m)∗(1m)*(1m)∗(1<<m)m)m)大小的矩阵. 然后 ...
- [Bzoj2004][Hnoi2010]Bus 公交线路(状压dp&&矩阵加速)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2004 看了很多大佬的博客才理解了这道题,菜到安详QAQ 在不考虑优化的情况下,先推$dp ...
- BZOJ 4000: [TJOI2015]棋盘( 状压dp + 矩阵快速幂 )
状压dp, 然后转移都是一样的, 矩阵乘法+快速幂就行啦. O(logN*2^(3m)) ------------------------------------------------------- ...
随机推荐
- Vulnhub实战-grotesque3靶机👻
Vulnhub实战-grotesque3靶机 靶机地址:http://www.vulnhub.com/entry/grotesque-301,723/ 1.靶机描述 2.主机探测,端口扫描 我们在vm ...
- .Net 5下的单文件部署
由于.net程序没有静态链接,一直缺乏单文件部署这种干净的发布方案.对客户端程序发布并不是很友好.在之前的.net framework下,有ILMerge合并程序集,以及LibZ的嵌入资源文件等第三方 ...
- MySQL:基础语法-2
MySQL:基础语法-2 记录一下 MySQL 基础的一些语法,便于查询,该部分内容主要是参考:bilibili 上 黑马程序员 的课程而做的笔记,由于时间有点久了,课程地址忘记了 上文MySQL:基 ...
- [敏捷软工团队博客]Beta阶段测试报告
项目 内容 2020春季计算机学院软件工程(罗杰 任健) 博客园班级博客 作业要求 Beta阶段测试报告 我们在这个课程的目标是 在团队合作中锻炼自己 这个作业在哪个具体方面帮助我们实现目标 对Bet ...
- BUAA 软工 个人博客作业(一)
项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人博客作业 我在这个课程的目标是 通过阅读<构建之法>大致了解软件工程 这个作业在哪 ...
- Noip模拟47 2021.8.25
期望得分:55+24+53 实际得分:0+0+3 乐死 累加变量清零了吗? 打出更高的部分分暴力删了吗? 样例解释换行你看见了吗? T1 Prime 打出55分做法没删原来的暴力,结果就轻松挂55分 ...
- [火星补锅] siano 神奇的线段树
前言: 本来以为很难打的,没想到主干一次就打对了,然而把输入的b和d弄混了,这sb错误调了两个小时... 解析: 神奇的线段树.注意到有一个性质,无论怎么割草,生长速度快的一定不会比生长速度慢的矮.因 ...
- 2021.8.13考试总结[NOIP模拟38]
T1 a 入阵曲.枚举矩形上下界,之后从左到右扫一遍.用树状数组维护前缀和加特判可以$A$,更保险要脸的做法是双指针扫,因为前缀和单调不减. $code:$ 1 #include<bits/st ...
- python基础语法--字典的遍历
原文链接:https://blog.csdn.net/normang/article/details/55804231 (1)遍历key值 >>> a {'a': '1', 'b': ...
- 【浏览器】聊聊DOM
[浏览器]聊聊DOM 博客说明 文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢! 说明 作为前端开发,在以前的工作中大多是和DOM打交道,到 ...