Codeforces917C. Pollywog
$n \leq 1e8$个石头,$x \leq 8$个蝌蚪一开始在最左边$x$个石子,要跳到最右的$x$个,每次只能最左边的蝌蚪跳一次,一个石头不能站两个蝌蚪,跳可以跳$1到k,x \leq k \leq 8$步,跳$i$步的代价是$cost_i$,还有$q \leq 25$个神奇石头,跳上去代价会$+w_i$,$w_i$可能为负数。问完成跳跃的最小代价。
不知道跳蝌蚪是什么操作只听过跳蛤,大概是变相膜?
好的严肃。从小数字$x$和$k$入手。由于每次只有最左的蝌蚪会跳,所以这$x$个蝌蚪一定每时每刻都在某连续的$k$个石头上。记这$k$个石头最左的那个(不一定上面有蝌蚪)为$i$,那么$i$处右边$k$个石子上的蝌蚪状态可以用二进制表示,最多是$C_8^4=70$个状态,挺小。这样就可以做转移了,转移复杂度是$C_k^x*k$,再乘个$n$直接爆炸。不过我们来看这个转移,$dp(i,j)=dp(i-1,k)+cost_t$,想到啥了?走若干步的最短路!这是可以用矩乘优化的,于是在不考虑$q$时,可以做$log_2n*(C_k^x)^3$的$dp$。
然后来看$q$。一块神奇石头影响了$k$块地(di)的(de)转移,因此最多会有$q*k$块地受影响,挺小,矩乘到这些地段时停住,暴力转移。最终复杂度$log_2n*(C_k^x)^3+qk^2C_k^x$。
//#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
//#include<map>
#include<math.h>
//#include<time.h>
//#include<complex>
#include<algorithm>
using namespace std; int X,K,n,m,q;
#define LL long long
const LL inf=1e18;
struct Mat
{
LL a[][];
Mat() {for (int i=;i<=;i++) for (int j=;j<=;j++) a[i][j]=inf;}
Mat operator * (const Mat &b)
{
Mat ans;
for (int k=;k<=m;k++)
for (int i=;i<=m;i++)
for (int j=;j<=m;j++)
ans.a[i][j]=min(ans.a[i][j],a[i][k]+b.a[k][j]);
return ans;
}
}base,f; Mat pow(Mat a,int b)
{
Mat ans,tmp=a; for (int i=;i<=m;i++) ans.a[i][i]=;
while (b)
{
if (b&) ans=ans*tmp;
tmp=tmp*tmp; b>>=;
}
return ans;
} int state[],ls,who[];
struct Ran{int l,r;}qq[],ran[]; int len;
LL g[],h[];int cost[];
struct Block{int pos,w;}ww[];
bool cmpww(const Block &a,const Block &b) {return a.pos<b.pos;}
struct Hash
{
int first[],le; struct Edge{int to,v,next;}edge[];
Hash() {le=;}
void insert(int x,int y) {int h=x%; Edge &e=edge[le]; e.to=x; e.v=y; e.next=first[h]; first[h]=le++;}
int find(int x) {int h=x%; for (int i=first[h];i;i=edge[i].next) if (edge[i].to==x) return edge[i].v; return -2e9;}
}ha; int main()
{
scanf("%d%d%d%d",&X,&K,&n,&q);
for (int i=;i<=K;i++) scanf("%d",&cost[i]);
for (int i=;i<=q;i++) scanf("%d%d",&ww[i].pos,&ww[i].w); sort(ww+,ww++q,cmpww);
LL ans=; for (int &i=q;i;i--) if (ww[i].pos>=n-X+) ans+=ww[i].w; else break;
for (int i=;i<=q;i++) ha.insert(ww[i].pos,ww[i].w);
for (int i=;i<=q;i++) qq[i].l=max(ww[i].pos-K,),qq[i].r=ww[i].pos;
len=; for (int i=;i<=q;i++)
{
if (len && qq[i].l<=ran[len].r+) ran[len].r=qq[i].r;
else len++,ran[len].l=qq[i].l,ran[len].r=qq[i].r;
}
ls=; for (int i=;i<(<<K);i++)
{
int cnt=;
for (int j=;j<K;j++) if ((i>>j)&) cnt++;
if (cnt==X) ls++,state[i]=ls,who[ls]=i;
} m=ls;
for (int i=;i<=ls;i++)
{
int s=who[i]>>;
if ((who[i]&)==) base.a[i][state[s]]=;
else for (int j=;j<=K;j++) if (((s>>(j-))&)==) base.a[i][state[s|(<<(j-))]]=cost[j];
}
f.a[][]=; ran[].r=;
for (int i=;i<=len;i++)
{
f=f*pow(base,ran[i].l-ran[i-].r-);
for (int j=;j<=ls;j++) g[j]=f.a[][j];
for (int j=ran[i].l;j<=ran[i].r;j++)
{
for (int k=;k<=ls;k++) h[k]=inf;
for (int k=;k<=ls;k++)
{
int s=who[k]>>;
if ((who[k]&)==) h[state[s]]=min(h[state[s]],g[k]);
else for (int l=,tmp;l<=K;l++) if (((s>>(l-))&)==)
{
int ns=s|(<<(l-));
if ((tmp=ha.find(j+l-))!=-2e9) h[state[ns]]=min(h[state[ns]],g[k]+cost[l]+tmp);
else h[state[ns]]=min(h[state[ns]],g[k]+cost[l]);
}
}
for (int k=;k<=ls;k++) g[k]=h[k];
}
for (int j=;j<=ls;j++) f.a[][j]=g[j];
}
f=f*pow(base,n-X+-ran[len].r);
printf("%lld\n",ans+f.a[][]);
return ;
}
Codeforces917C. Pollywog的更多相关文章
- CF917C Pollywog —— 状压DP + 矩乘优化
C. Pollywog 题目描述 原题题目链接.题目大意为:有$x$只蝌蚪,在$n$个石头中的最左端的$x$个石头上,这$n$个石头是在同一直线上的.每一次只能最左边的一个蝌蚪进行跳跃,并且只能跳$1 ...
- Codeforces 917C - Pollywog(状压 dp+矩阵优化)
UPD 2021.4.9:修了个 typo,为啥写题解老出现 typo 啊( Codeforces 题目传送门 & 洛谷题目传送门 这是一道 *2900 的 D1C,不过还是被我想出来了 u1 ...
- Pollywog CodeForces - 917C (状压)
链接 大意: 一共n个格子, 初始$x$只蝌蚪在前$x$个格子, 每次最左侧的蝌蚪向前跳, 跳跃距离在范围[1,k], 并且每只蝌蚪跳跃都有一定花费, 有$q$个格子上有石头, 若有蝌蚪跳到某块石头上 ...
随机推荐
- java 自定义注解,并使用示例
场景: 对需要校验 手机验证码和短信验证码的controller方法添加 自定义的注解 @CheckType 1. 定义注解 /** * 需要短信.验证码验证方法上的注解 * date: 2018年 ...
- AJPFX关于集合的几种变量方式
package com.java.test; import java.util.ArrayList;import java.util.Enumeration;import java.util.Iter ...
- JS进阶-闭包的几种常见形式
作用域链: //作用域链 var a = 1; function test() { var b =2; return a; } alert(test());//弹出1: alert(b);//不能获取 ...
- 使用cordova把h5应用打包成apk
由于h5应用开发不是本例重点,因此直接提供一个最简单的h5应用代码,此应用使用vue-cli框架开发 此h5应用叫vue1,用webstrom打开vue1,进行npm install安装引用 vue1 ...
- 我来说说java的NIO
Java NIO的出现旨在提高文件的读写速度,当然IO用NIO重新实过,所以我们不用显示的调用NIO也能享受这种高效的文件读写. Java NIO的高效得益于其两大"助手":C ...
- Android(java)学习笔记168:Activity 4 种启动模式
1. 任务栈(task stack): 任务栈 是用来记录用户操作的行为,维护一个用户体验. 一个应用程序一般都是由多个activity组成的. 任务栈(task stack)记录存放用户开启的act ...
- DROP DATABASE - 删除一个数据库
SYNOPSIS DROP DATABASE name DESCRIPTION 描述 DROP DATABASE 删除一个现存数据库的目录入口并且删除包含数据的目录. 只有数据库所有者能够执行这条命令 ...
- CPP-STL:随机数发生器random_shuffle
//--------------------------------------------------------------------------- #include <string.h& ...
- 模板引擎freemarker的使用(一)
配置 了解和学习一下freemarker在项目中的配置与使用,顺便记录下来,知识源于分享,进步源于交流... 我是在ssm中配置的. maven 中需要引入的依赖 <!-- freemarker ...
- PHP20 PHP面向对象辅助
学习要点 常用函数 命名空间 类的自动加载 常用函数 class_exists 作用:检查类是否已定义 语法格式: bool class_exists ( string $class_name [, ...