传送门

这里设\(f_i\)表示时刻\(i\)的答案

转移的话在\([i-p+1,i-1]\)之间枚举j,然后考虑从哪个点走过来

复杂度为\(O(n^3)\)

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define inf 999999999 using namespace std;
const int N=1000+10;
il LL rd()
{
re LL x=0,w=1;re char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int f[N],a[N][N],c[N],n,m,p; int main()
{
n=rd(),m=rd(),p=rd();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[(i-j+n*m)%n+1][j]=rd();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]+=a[i][j-1];
for(int i=1;i<=n;i++) c[i]=rd();
memset(f,-63,sizeof(f));
f[0]=0;
for(int i=1;i<=m;i++)
for(int j=max(0,i-p);j<i;j++)
{
int cn=-inf;
for(int k=1;k<=n;k++) cn=max(cn,a[(k-i+n*m)%n+1][i]-a[(k-i+n*m)%n+1][j]-c[(k-i+j+n*m)%n+1]);
f[i]=max(f[i],f[j]+cn);
}
printf("%d\n",f[m]);
return 0;
}

但是发现重新选择的次数越多,负价值似乎也越多,考虑重设\(f_{i,j}\)表示时刻\(i\)走到\(j\)的答案,转移要么这一点重新选一个机器人,要么从之前的合法的\(f_{i-1,(j-1)mod n+1}\)转移

// luogu-judger-enable-o2
/*省略*/ using namespace std;
const int N=1000+10;
il LL rd()
{
/*省略*/
}
int F[N],f[N][N],ti[N][N],a[N][N],la[N],c[N],n,m,p; //la[i]=i前一个位置 int main()
{
n=rd(),m=rd(),p=rd();
for(int j=2;j<=n;j++) la[j]=j-1;
la[1]=n;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=rd();
memset(f,-63,sizeof(f));
memset(F,-63,sizeof(F));
for(int j=1;j<=n;j++) c[j]=rd();
for(int j=1;j<=n;j++)
{
ti[1][j]=1,f[1][j]=a[la[j]][1]-c[la[j]];
F[1]=max(F[1],f[1][j]);
}
for(int i=2;i<=m;i++)
for(int j=1;j<=n;j++)
{
ti[i][j]=1,f[i][j]=F[i-1]-c[la[j]];
if(ti[i-1][la[j]]<p&&f[i][j]<f[i-1][la[j]]) ti[i][j]=ti[i-1][la[j]]+1,f[i][j]=f[i-1][la[j]];
f[i][j]+=a[la[j]][i];
F[i]=max(F[i],f[i][j]);
}
printf("%d\n",F[m]);
return 0;
}

乍一看好像是对的

但是会被下面这个数据\(\mathfrak{X}\)掉(huaji)

5 4 3
1 1 1 138
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
233 66 66 66 66

因为上一个代码转移是第一个用3s,第二个用1s,但最优策略是两个都用2s\(\color{#FFFFFF}{-1s\&+1s}\)

考虑如果这样转移

\[f_{i,j}=max(F_{i-k}+a_{i,j}-a_{i-k,j-k}-c_{j-k+1})$$(为了简便不取膜)

其中$a_{i,j}$为**$i$时刻到$j$位置**的前缀和
```cpp
for(int j=1;j<=n;j++)
for(int i=1;i<=m;i++)
a[i][j]=rd();
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
a[i][j]+=a[i-1][(j-1+n-1)%n+1];
```

把$a_{i,j}$拎出去
$$f_{i,j}=max(F_{i-k}-a_{i-k,j-k}-c_{j-k+1})+a_{i,j}\]

令\(b_{i,j}=F_{i}-a_{i,j}-c_{j+1}\)

则$$f_{i,j}=max(b_{i-k,j-k})+a_{i,j}$$

k的范围为\([1,n]\),所以相当于是滑动的区间最大值虽然是斜的,单调队列即可

代码

// luogu-judger-enable-o2
/*省略*/ using namespace std;
const int N=1000+10;
il LL rd()
{
/*省略*/
}
int F[N],f[N][N],a[N][N],c[N],nt[N],n,m,p; //nt[i]=i后一个位置
int q[N][N],hd[N],ti[N][N],tl[N]; int main()
{
n=rd(),m=rd(),p=rd();
for(int i=1;i<n;i++) nt[i]=i+1;
nt[n]=1;
for(int j=1;j<=n;j++)
for(int i=1;i<=m;i++)
a[i][j]=rd();
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
a[i][j]+=a[i-1][(j-1+n-1)%n+1];
for(int i=1;i<=n;i++) c[i]=rd();
memset(F,-63,sizeof(F));
memset(f,-63,sizeof(f));
F[0]=0;for(int i=1;i<=n;i++) hd[i]=tl[i]=1,q[i][1]=-c[i];
for(int j=1;j<=n;j++)
{
f[1][j]=a[1][j]-c[j];
F[1]=max(F[1],f[1][j]);
}
for(int j=1;j<=n;j++)
{
int b=F[1]-a[1][j]-c[nt[j]];
while(hd[j]<=tl[j]&&b>=q[j][tl[j]]) --tl[j];
q[j][++tl[j]]=b,ti[j][tl[j]]=1;
}
for(int i=2;i<=m;i++)
{
for(int j=1,ii=(1-i+n*m)%n+1;j<=n;j++,ii=nt[ii])
{
while(hd[ii]<=tl[ii]&&ti[ii][hd[ii]]+p<i) ++hd[ii];
f[i][j]=q[ii][hd[ii]]+a[i][j];
F[i]=max(F[i],f[i][j]);
}
for(int j=1,ii=(1-i+n*m)%n+1;j<=n;j++,ii=nt[ii])
{
int b=F[i]-a[i][j]-c[nt[j]];
while(hd[ii]<=tl[ii]&&b>=q[ii][tl[ii]]) --tl[ii];
q[ii][++tl[ii]]=b,ti[ii][tl[ii]]=i;
}
}
printf("%d\n",F[m]);
return 0;
}

luogu P1070 道路游戏的更多相关文章

  1. [luogu]P1070 道路游戏[DP]

    [luogu]P1070 道路游戏 题目描述小新正在玩一个简单的电脑游戏.游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针 ...

  2. 洛谷 P1070 道路游戏 解题报告

    P1070 道路游戏 题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有\(n\)个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依 ...

  3. 洛谷P1070 道路游戏

    P1070 道路游戏 题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依次将 ...

  4. 洛谷 P1070 道路游戏 DP

    P1070 道路游戏 题意: 有一个环,环上有n个工厂,每个工厂可以生产价格为x的零钱收割机器人,每个机器人在购买后可以沿着环最多走p条边,一秒走一条,每条边不同时间上出现的金币是不同的,问如何安排购 ...

  5. 【题解】洛谷P1070 道路游戏(线性DP)

    次元传送门:洛谷P1070 思路 一开始以为要用什么玄学优化 没想到O3就可以过了 我们只需要设f[i]为到时间i时的最多金币 需要倒着推回去 即当前值可以从某个点来 那么状态转移方程为: f[i]= ...

  6. 洛谷P1070 道路游戏(dp+优先队列优化)

    题目链接:传送门 题目大意: 有N条相连的环形道路.在1-M的时间内每条路上都会出现不同数量的金币(j时刻i工厂出现的金币数量为val[i][j]).每条路的起点处都有一个工厂,总共N个. 可以从任意 ...

  7. Luogu 1070 道路游戏

    看完题面想了一会发现只会写$n^3$,愣了一会才想出了单调队列优化的做法. 90分算法: 设$f_{i, j, k}$表示第$i$分钟在第$j$座城市已经走了$k$步的最大价值,转移显然,时间复杂度$ ...

  8. P1070 道路游戏

    题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依次将这 n 个机器人工厂编 ...

  9. 洛谷 P1070 道路游戏(noip 2009 普及组 第四题)

    题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有 nn个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依次将这 nn个机器人工厂编 ...

随机推荐

  1. python之pygal:掷两个不同的骰子并统计大小出现次数

    代码示例: # 掷两个不同的骰子并统计大小出现次数 import pygal from die_class import Die die = Die(6) # 实例化一个六面的骰子对象 die_10 ...

  2. LODOP、C-LODOP注册号的区别

    LODOP是一款免费的web打印控件,预览打印后无水印,是免费的,直接打印会在纸张下方有个水印“本页由XXX试用版输出”,通常商用打印较多,常用直接打印,这种时候可以购买注册号去水印. LODOP注册 ...

  3. ceph radosgw-admin的操作

    常用操作: 生成一新用户: 在两个集群当中都创建相同的管理用户 radosgw-admin user create --uid=admin --display-name=admin --access_ ...

  4. KEYENCE Programming Contest 2019 自闭记

    A:签到. #include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> ...

  5. MT【54】一道二次函数问题的几何意义

    [Rather less, but better.]----卡尔·弗里德里希·高斯(1777-1855) (2016诸暨质检18)已知$f(x)=x^2-a|x-1|+b(a>0,b>-1 ...

  6. 自学Zabbix3.12.5-动作Action-Condition配置

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 3.12.5 自学Zabbix3.12.5-动作Action-Condition配置 报警,肯定是 ...

  7. 自学Zabbix8.1 Regular expressions 正则表达式

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix8.1 Regular expressions 正则表达式 1. 配置 点击Adm ...

  8. activity window view 关系

    1.Activity , Window和View的关系是什么? 跟踪Activity的源码就会发现:Activity.attch() -> PolicyManager -> Policy ...

  9. android 下改变默认的checkbox的 选中 和被选中 图片

    1.   先导入  checked.png 和 unchecked.png 两张图片 2.  在res/drawable下面,添加selector (如 check_state.xml)文件: < ...

  10. linux已开机时间 系统信息

    linux 查看系统运行时间 (从开机当现在的开机时间) 1.uptime命令输出:16:11:40 up 59 days, 4:21, 2 users, load average: 0.00, 0. ...