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 ...
随机推荐
- SQLServer2008 有用的判断函数
ISNULL(参数1,参数2) 若参数1为空,则返回参数2 NULLIF(参数1,参数2) 若参数1和参数2不等,则返回参数1 若参数1和参数2相等,则返回NULL 例子:ISNULL(NULLIF( ...
- vue.js $set的使用 数组
[javascript] view plain copy <!DOCTYPE html> <html lang="en"> <head> < ...
- Android环境的搭建遇到的问题和解决方案
安卓环境的搭建,我花了将近一天的时间,在最后终于找到了一个比较好的方案. 第一个问题是安卓的官网(http://developer.android.com)很难登录.SDK和ADT都是需要在官网上下载 ...
- 使用T-sql建库建表建约束
为什么要使用sql语句建库建表? 现在假设这样一个场景,公司的项目经过测试没问题后需要在客户的实际环境中进行演示,那就需要对数据进行移植,现在问题来了:客户的数据库版本和公司开发阶段使用的数据库不兼容 ...
- 水仙花数------"水仙花数 "是指一个三位数,其各位数字立方和等于该数本身。(for循环的嵌套)
package com.zuoye.test;//打印出所有的 "水仙花数 ",所谓 "水仙花数 "是指一个三位数,//其各位数字立方和等于该数本身.//例如: ...
- 多开 MFC线程
序言:我才编程几年啊!就要处理多线程.对于只写函数的我,这难度简直了!不过MFC的多线程,貌似比较简单,还能处理的了. (1).开MFC多个线程 在视频采集的过程中,如果不使用媒体计数器,会造成主线程 ...
- React Native Windows下环境安装(一)
1.安装chocolatey 以管理员权限运行命令提示符(cmd.exe) @powershell -NoProfile -ExecutionPolicy Bypass -Command " ...
- Android 性能测试初探(二)
书接前文 Android 性能测试初探(一).上回大体介绍了下在 android 端的性能测试项,现在我们就细节测试项做一些阐述(包括如何自己 DIY 测试). 首先我们来说说启动时间.关于应用的启动 ...
- 【剑指Offer】28、数组中出现次数超过一半的数字
题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 例如:输入如下所示的一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过 ...
- 继承(day09)
二十一 继承(Inheritance) ... 子类的构造函数和析构函数 5.1 子类的构造函数 )如果子类构造函数没有显式指明基类子对象的初始化方式,那么该子对象将以无参方式被初始化. )如果希望基 ...