0x57 倍增优化DP
真的是下定了巨大的决心来搞这一讲,果不其然耗了一晚上
开车旅行(真的是NOIP的题吗怎么这么恐怖)
首先,先用set把小A和小B从城市i出发,到达的下一个城市预处理出来。
f[i][j][k]表示走了2^i天,j城市出发,k表示谁开车,到达那个城市。
转移就是f[i][j][k]=f[i-1][f[i-1][j][k]][k] 相信很好理解
特别的i-1==0时,因为k是奇数,开车的人是变化的,所以f[i][j][k]=f[i-1][f[i-1][j][k]][k^1]
令da[i][j][k],db[i][j][k],分别表示小A和小B这个状态下走的路程
对于询问1,枚举所有的城市作为起点,然后基于二进制划分的思想,倒着for一步步在满足走的总路程<=x0的情况下前进,这样可以计算出小A走的路程和小B走的路程。找最大比值即可。
询问二就直接询问小A走的路程和小B走的路程了。同理可求。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;
typedef long long LL; int h[];
struct snode
{
int id,h;
snode(){}
snode(int ID,int H){id=ID;h=H;}
friend bool operator <(snode s1,snode s2){return s1.h<s2.h;}
};
set<snode>S;
set<snode>::iterator it,lt,rt;
int g[],I;
bool cmp(int g1,int g2){return (abs(h[g1]-h[I])<abs(h[g2]-h[I]))||(abs(h[g1]-h[I])==abs(h[g2]-h[I])&&h[g1]<h[g2]);} int Ago[],Bgo[];
int f[][][]; LL da[][][],db[][][]; LL A,B;
void solve(int now,int x0)
{
A=B=; int k=;
for(int i=;i>=;i--)
if(f[i][now][k]!=&&da[i][now][k]+db[i][now][k]<=x0)
{
x0-=da[i][now][k]+db[i][now][k];
A+=da[i][now][k],B+=db[i][now][k];
if(i==)k^=;
now=f[i][now][k];
}
} int main()
{
int n;
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d",&h[i]);
memset(Ago,,sizeof(Ago));
memset(Bgo,,sizeof(Bgo));
for(int i=n;i>=;i--)
{
S.insert(snode(i,h[i]));
it=lt=rt=S.find(snode(i,h[i]));
int m=;
if(lt!=S.begin())
{
lt--,g[++m]=(*lt).id;
if(lt!=S.begin())lt--,g[++m]=(*lt).id;
}
rt++;
if(rt!=S.end())
{
g[++m]=(*rt).id;
rt++;if(rt!=S.end())g[++m]=(*rt).id;
}
I=i;sort(g+,g+m+,cmp);
if(m>)Ago[i]=g[];
if(m>)Bgo[i]=g[];
} memset(f,,sizeof(f));
for(int i=;i<=n;i++)
{
if(Ago[i]!=) f[][i][]=Ago[i], da[][i][]=abs(h[Ago[i]]-h[i]), db[][i][]=;
if(Bgo[i]!=) f[][i][]=Bgo[i], da[][i][]=, db[][i][]=abs(h[Bgo[i]]-h[i]);
}
for(int i=;i<=;i++)
for(int j=;j<=n;j++)
for(int k=;k<=;k++)
{
int l=k;if(i==)l=k^; if(f[i-][j][k]>)f[i][j][k]=f[i-][f[i-][j][k]][l];
if(f[i][j][k]>)
{
da[i][j][k]=da[i-][j][k]+da[i-][f[i-][j][k]][l];
db[i][j][k]=db[i-][j][k]+db[i-][f[i-][j][k]][l];
}
} int x0,ans;LL ansA=,ansB=;
scanf("%d",&x0);
for(int i=;i<=n;i++)
{
solve(i,x0); if(B==)A=;
if(A*ansB<ansA*B||(A*ansB==ansA*B&&h[i]>h[ans]))ansA=A,ansB=B,ans=i;
}
printf("%d\n",ans); int Q,x,y;
scanf("%d",&Q);
while(Q--)
{
scanf("%d%d",&x,&y);
solve(x,y);
printf("%lld %lld\n",A,B);
} return ;
}
开车旅行
Count The Repetitions
f[j][i]表示从s1第i个字符开始,能够表示出s2 2^j最少需要多少字符。
就有f[j][i]=f[j-1][i]+f[j-1][((i+f[j-1][i])-1)%s1len+1]
最后就枚举匹配的起始点,同样在不超过s1len*n1的情况下用二进制一步步跳,记录当前起始点的最优解更新答案就好了。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL; char s1[],s2[];
LL f[][];
int main()
{
freopen("2.in","r",stdin);
freopen("2.out","w",stdout);
while()
{
int n2,n1;
scanf("%s",s2+);if(s2[]=='}')break;
scanf("%d%s%d",&n2,s1+,&n1);
int s2len=strlen(s2+),s1len=strlen(s1+); bool bk=false;
for(int i=;i<=s1len;i++)
{
int p=i;f[][i]=;
for(int j=;j<=s2len;j++)
{
int cc=;
while(s1[p]!=s2[j])
{
p=p%s1len+;
cc++;if(cc>=s1len){printf("0\n");bk=true;break;}
}
p=p%s1len+;
f[][i]+=cc+;
if(bk==true)break;
}
if(bk==true)break;
}
if(bk==true)continue; for(int j=;j<=;j++)
for(int i=;i<=s1len;i++)
f[j][i]=f[j-][i]+f[j-][((i+f[j-][i])-)%s1len+]; LL m=;
for(int i=;i<=s1len;i++)
{
int x=i;LL ans=;
for(int j=;j>=;j--)
if(x+f[j][(x-)%s1len+]-<=s1len*n1)
x+=f[j][(x-)%s1len+], ans+=(<<j);
m=max(m,ans);
}
printf("%lld\n",m/n2);
}
return ;
}
Count The Repetitions
好像都是先预处理出下一步的状态,然后二进制划分啊
0x57 倍增优化DP的更多相关文章
- HZOJ 20190727 随(倍增优化dp)
达哥T1 实际上还是挺难的,考试时只qj20pts,还qj失败 因为他专门给出了mod的范围,所以我们考虑把mod加入时间复杂度. $50\%$算法: 考虑最暴力的dp,设$f[i][j]$表示进行$ ...
- $Noip2012\ Luogu1081$ 开车旅行 倍增优化$ DP$
Luogu Description Sol 1.发现对于每个城市,小A和小B的选择是固定的,可以预处理出来,分别记为ga[],gb[] 2.并且,只要知道了出发城市和出发天数,那么当前城市和小A,小B ...
- CodeForces - 1175E Minimal Segment Cover (倍增优化dp)
题意:给你n条线段[l,r]以及m组询问,每组询问给出一组[l,r],问至少需要取多少个线段可以覆盖[l,r]区间中所有的点. 如果贪心地做的话,可以求出“从每个左端点l出发选一条线段可以到达的最右端 ...
- $CH0601\ Genius\ ACM$ 倍增优化DP
ACWing Description 给定一个长度为N的数列A以及一个整数T.我们要把A分成若干段,使得每一段的'校验值'都不超过N.求最少需要分成几段. Sol 首先是校验值的求法: 要使得'每对数 ...
- POJ 1014 Dividing(多重背包, 倍增优化)
Q: 倍增优化后, 还是有重复的元素, 怎么办 A: 假定重复的元素比较少, 不用考虑 Description Marsha and Bill own a collection of marbles. ...
- Codeforces 356D 倍增优化背包
题目链接:http://codeforces.com/contest/356/problem/D 思路(官方题解):http://codeforces.com/blog/entry/9210 此题需要 ...
- 矩阵乘法优化DP复习
前言 最近做毒瘤做多了--联赛难度的东西也该复习复习了. Warning:本文较长,难度分界线在"中场休息"部分,如果只想看普及难度的可以从第五部分直接到注意事项qwq 文中用(比 ...
- bzoj-4518 4518: [Sdoi2016]征途(斜率优化dp)
题目链接: 4518: [Sdoi2016]征途 Description Pine开始了从S地到T地的征途. 从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站. Pine计划用m天到达T地 ...
- bzoj-1096 1096: [ZJOI2007]仓库建设(斜率优化dp)
题目链接: 1096: [ZJOI2007]仓库建设 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L ...
随机推荐
- lsit集合去重复 顶级表达式
updateList = updateList.Where((x, i) => updateList.FindIndex(z => z.ID == x.ID) == i).ToList() ...
- ESB报文自动生成工具
为了提高日常工作效率,自己在闲暇时间写了一款工具,功能界面如下图所示: 从ESB文档中复制报文字段.字段类型.报文字段注释,选择生成文件路径并输入文件名: 输入完毕后点击生成按钮,自动生成Contex ...
- MainActivity 多个Fragment 内存被回收
0. 前言 应用首页采用Activity +Tab 模式,多个Fragment 替换显示隐藏 FragmentTransaction transaction = getSupportFragmentM ...
- PHP执行Mysql数据库的备份和还原
使用mysqldump命令备份 mysqldump命令将数据库中的数据备份成一个文本文件.表的结构和表中的数据将存储在生成的文本文件中. mysqldump命令的工作原理很简单.它先查出需要备份的表的 ...
- (转)基于openlayers实现聚类统计展示
http://blog.csdn.net/gisshixisheng/article/details/46137015 概述: 在前面的博文中讲述过基于Arcgis for js如何实现聚类统计展示, ...
- NSURLProtectionSpace 证书认证的上下文
个NSURLProtectionSpace提供如下信息: //401的认证方式的realm字段的值 (NSString*)realm; //401的认证方式,指定是否密码发送安全. -(BOOL)re ...
- javeee 字节Buffered
package Zy; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io. ...
- python时间序列按频率生成日期
有时候我们的数据是按某个频率收集的,比如每日.每月.每15分钟,那么我们怎么产生对应频率的索引呢?pandas中的date_range可用于生成指定长度的DatetimeIndex.我们先看一下怎么生 ...
- php第七节课
多态,重载,克隆 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://ww ...
- Dell R720修改远程管理口的密码
今天有个客户需要通过远程管理口来查看系统事件日志,但是他们把初始密码改过并且还给忘记了.后来我决定进操作系统(cent os)进行修改.整个过程很简单,进入系统后只需要三个步骤就解决问题了 1.安装软 ...