C. Pollywog

题目描述

  原题题目链接。题目大意为:有$x$只蝌蚪,在$n$个石头中的最左端的$x$个石头上,这$n$个石头是在同一直线上的。每一次只能最左边的一个蝌蚪进行跳跃,并且只能跳$1$至$k$步,跳$i$步要花费$c_i$的体力。在蝌蚪跳跃时,是不能跳到已有蝌蚪的石头上。在这$n$个石头里面有$q$个石头是特殊的石头,跳上这$q$个石头中的第$p$个要额外花费$w_p$的体力值。问当所有蝌蚪跳到最右边的$x$个石头时的最小体力值。

思路

  首先,根据题意我们能知道所有的蝌蚪都一定在连续的$k$块石头上。现在进行一个小小的证明:假设这些蝌蚪不在连续的$k$块石头上,则最左边的蝌蚪在跳跃时一定会跳在最右边的蝌蚪的左边,不会使最右端点向右移动,但是因为最左边的蝌蚪跳动了,所以最左端点会向右移动,这样的话,区间就会缩短。知道当最左边的蝌蚪和最右边的蝌蚪的距离小于$k$时,才能在向右跳跃时将最右端点向右移动,又因为开始的时候所有的蝌蚪都在最左边的$x$个石头上,所以不会使区间大于$k$。

  因此我们就可以处理出来长度为$k$的所有的情况之间的转移。我们定义一个单位元矩阵,$num[i][j]$表示状态为$i$的石头转移成为状态为$j$的石头的花费。什么是状态为$i$的石头呢???我们将$i$转成二进制,这样我们就得到了一个$01$串,在这个$01$串中,$0$表示这个石头上没有蝌蚪,反之$1$表示有蝌蚪。因为我们一共就只需要枚举$k$块石头,并且只有$x$只青蛙,且$k,x \le 8$,所以最多就只有$C_8^4$种情况,将二进制串离散一下就好了。这就是预处理。

  我们得到了一个转移的邻接矩阵,我们就可以用这个矩阵来进行矩乘,先不考虑特殊的石头,所以就计算这个矩阵的$n-x$次幂就可以,$n-x$次幂的意思是,每一次都将当前$k$块石头向右进行移动一块石头,这样移动$n-x$次就是答案,但是特殊的石头要更改答案,所以我们到达一块特殊的石头,就停下来暴力就可以了。我们知道一块特殊的石头只能对$k$个转移带来影响。所以我们暴力停下来转移是可以的,时间复杂的是$O(k^2 \times q \times C_k^x)$。

代码

#include <cstdio>
#include <algorithm>
using namespace std;
#define inf 1e18
#define N 10
int x,k,n,q,cnt;long long num[N];int bel[1<<10];
struct Square
{
long long num[71][71];
Square()
{for(int i=1;i<=70;i++) {for(int j=1;j<=70;j++) num[i][j]=inf;num[i][i]=0;}}
Square operator * (const Square &a) const
{
Square tmp;
for(int i=1;i<=cnt;i++)
tmp.num[i][i]=inf;
for(int i=1;i<=cnt;i++)
for(int j=1;j<=cnt;j++)
for(int k=1;k<=cnt;k++)
tmp.num[i][j]=min(tmp.num[i][j],num[i][k]+a.num[k][j]);
return tmp;
}
Square operator ^ (const int &x)
{
if(!x) return Square();
Square tmp,tmp1;int times=x;
for(int i=1;i<=cnt;i++)
for(int j=1;j<=cnt;j++) tmp1.num[i][j]=num[i][j];
while(times) {if(times&1) tmp=tmp*tmp1;times>>=1;tmp1=tmp1*tmp1;}
return tmp;
}
}one;
struct Stone
{int place;long long val;}stone[30];
bool calc(int tmp)
{
int many=0;
for(int i=1;i<=8;i++) if(tmp&(1<<(i-1))) many++;
return many==x;
}
bool cmp(const Stone &a,const Stone &b)
{return a.place<b.place;}
int main()
{
scanf("%d%d%d%d",&x,&k,&n,&q);
for(int i=0;i<=(1<<k)-1;i++) if(calc(i)) bel[i]=++cnt;
for(int i=1;i<=k;i++) scanf("%lld",&num[i]);
for(int i=1;i<=q;i++) scanf("%d%lld",&stone[i].place,&stone[i].val);
sort(stone+1,stone+q+1,cmp);
for(int i=1;i<=cnt;i++) one.num[i][i]=inf;
for(int i=1;i<=(1<<k)-1;i++)
{
if(!bel[i]) continue;
if(i&1)
{for(int j=1;j<=k;j++)
{if(!((1<<j)&i)) one.num[bel[i]][bel[((1<<j)|i)>>1]]=num[j];}}
else one.num[bel[i]][bel[i>>1]]=0;
}
int now=1;long long sum=0;Square ans;
for(int i=1;i<=q;i++)
{
if(stone[i].place>n-x) {sum+=stone[i].val;continue;}
ans=ans*(one^(stone[i].place-now)),now=stone[i].place;
for(int j=1;j<=(1<<k)-1;j+=2)
if(bel[j])
for(int k=1;k<=cnt;k++)
ans.num[k][bel[j]]+=stone[i].val;
}
ans=ans*(one^(n-x+1-now));
printf("%lld",ans.num[1][1]+sum);
}

  

CF917C Pollywog —— 状压DP + 矩乘优化的更多相关文章

  1. T2988 删除数字【状压Dp+前缀和优化】

    Online Judge:从Topcoder搬过来,具体哪一题不清楚 Label:状压Dp+前缀和优化 题目描述 给定两个数A和N,形成一个长度为N+1的序列,(A,A+1,A+2,...,A+N-1 ...

  2. 你必须知道的基本位运算技巧(状压DP、搜索优化都会用到)

    一. 位操作基础 基本的位操作符有与.或.异或.取反.左移.右移这6种,它们的运算规则如下所示: 符号 描述 运算规则 & 与 两个位都为1时,结果才为1 | 或 两个位都为0时,结果才为0 ...

  3. 状压DP复习笔记

    前言 复习笔记第4篇.CSP RP++. 引用部分为总结性内容. 0--P1433 吃奶酪 题目链接 luogu 题意 房间里放着 \(n\) 块奶酪,要把它们都吃掉,问至少要跑多少距离?一开始在 \ ...

  4. Codeforces 917C - Pollywog(状压 dp+矩阵优化)

    UPD 2021.4.9:修了个 typo,为啥写题解老出现 typo 啊( Codeforces 题目传送门 & 洛谷题目传送门 这是一道 *2900 的 D1C,不过还是被我想出来了 u1 ...

  5. bzoj2004 矩阵快速幂优化状压dp

    https://www.lydsy.com/JudgeOnline/problem.php?id=2004 以前只会状压dp和矩阵快速幂dp,没想到一道题还能组合起来一起用,算法竞赛真是奥妙重重 小Z ...

  6. POJ1038 Bugs Integrated, Inc 状压DP+优化

    (1) 最简单的4^10*N的枚举(理论上20%) (2) 优化优化200^3*N的枚举(理论上至少50%) (3) Dfs优化状压dp O(我不知道,反正过不了,需要再优化)(理论上80%) (4) ...

  7. 【bzoj1097】[POI2007]旅游景点atr 状压dp+堆优化Dijkstra

    题目描述 FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情.经过这些城市的顺序不是完全随意的,比如说FGD不希望在刚吃过一顿大餐之后立刻去下一个 ...

  8. NOJ 1116 哈罗哈的大披萨 【淡蓝】 [状压dp+各种优化]

    我只能说,珍爱生命,远离卡常数的题...感谢陈老师和蔡神,没有他们,,,我调一个星期都弄不出来,,,, 哈罗哈的大披萨 [淡蓝] 时间限制(普通/Java) : 1000 MS/ 3000 MS   ...

  9. BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3336  Solved: 1936[Submit][ ...

随机推荐

  1. Winform VS2015打包

    首先 ,我们要去官网http://learn.flexerasoftware.com/content/IS-EVAL-InstallShield-Limited-Edition-Visual-Stud ...

  2. Android Studio 快捷键(包含自定义)终极版

      [F] [F] F2 在错误代码之间切换 F3 往前定位(Shift + F3:往后定位 )有问题 F4\Ctrl+鼠标点击\Ctrl+B 转到定义,查看类继承关系 F5 但不调试进入函数内部. ...

  3. jq相关细节-1

    animate/动画 所有用于动画的属性必须是数字的,除非另有说明:这些属性如果不是数字的将不能使用基本的jQuery功能.(例如,width, height或者left可以执行动画,但是backgr ...

  4. Spring MVC学习总结

    Spring MVC学习总结 Spring MVC学习路(一) 下载配置文件 Spring MVC学习路(二) 设置配置文件 Spring MVC学习路(三) 编写第一个demo Spring MVC ...

  5. 56、使用android studio(v1.3.*)修改包名 (rename package name)

    一.修改包名 ①选中目录,开始构造 在弹窗中选中Rename directory 在弹窗中选中Rename package 填写新的包名,点击Refactor 如果有警告,不用管它,直接点击Do Re ...

  6. ogre3D学习基础17 --- 如何手动创建ogre程序

    建立自己的Ogre程序 一直以来都是使用ExampleApplication.h来写程序,现在来看看它到底有什么神奇的地方. 首先,我们新建一个win32空项目 然后配置环境 最后新建define.c ...

  7. NSURLSession使用模板和AFNetworking使用模板(REST风格)

    1.NSURLSession使用模板 NSURLSession是苹果ios7后提供的api,用来替换 NSURLConnection会话指的是程序和服务器的通信对象//一.简单会话不可以配合会话(ge ...

  8. [URAL1519] Formula 1 [插头dp入门]

    题面: 传送门 思路: 插头dp基础教程 先理解一下题意:实际上就是要你求这个棋盘中的哈密顿回路个数,障碍不能走 看到这个数据范围,还有回路处理,就想到使用插头dp来做了 观察一下发现,这道题因为都是 ...

  9. [SDOI2009][bzoj1878] HH的项链 [莫队模板题]

    题面: 传送门 思路: 就是一道莫队的模板题目...... 开一个1000000的数组记录每个数出现的次数,然后每次从1到0或者从0到1更新答案 莫队讲解看这里:莫队 Code: #include&l ...

  10. BZOJ4516 [Sdoi2016]生成魔咒 【后缀自动机】

    题目 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例如 S=[1,2, ...