[APIO2015]巴厘岛的雕塑 贪心+DP+特殊数据优化
写了好久。。。。
刚刚调了一个小时各种对拍,,,,最后发现是多写了一个等号,,,,内心拒绝
表示一开始看真的是各种懵逼啊
在偷听到某位大佬说的从高位开始贪心后发现可做
首先考虑小数据(因为可以乱搞)
所以先从高位开始枚举位数:
for(int k=all; k ;k--)
ans表示当前答案,f[i][j]表示dp到第i为,分为j段,是否可以满足第k位为0
ans初始为0,每次DP完就修改ans,
所以枚举i和j,然后枚举上一段的结尾l,
由于是or,所以之前已经有的是消不掉的,
于是有 if(!f[l][j-1]) continue;
这样就可以保证之前的都已经满足了,所以只要考虑当前段就好了
sum[i]表示到i的前缀和。
先获取当前段大小now=sum[i] - sum[l]
所以如果now的第k位为0,并且之前的高位都不与当前ans冲突,就可以转移了
因为如果高位与ans冲突,而前面已经最优了,所以如果冲突只能是不那么优,
于是后面再优都补不回来了。其实这也是从高位贪心的意义所在
最后如果在f[n][A ~ B]中有任意一个为true的话,ans就不用修改(因为默认已经是0了)
而如果一个都没有,那么就将ans的当前位变成1,
那么考虑如何判断,
首先运算符肯定只能用or,不然是会遗漏信息的(也许可以用其他的吧,但是我没想到)
考虑这样两个二进制串:
now :101100 1011
ans : 101100 0000
中间的空格代表把第k位和后面隔开,
通过一些二进制的基本性质(其实也是所有进制的基本性质)可以发现,
如果前面都是相同的话,因为ans的小于k的位数都还不确定,都是0,
所以最大相差也就是2^(k-1),
反之如果前面有冲突,那么由于冲突在前面,相差一定会超过2^(k-1),
所以直接判断now和ans的差就可以了?
不是!
因为now是中间过程,所以now是可能小于ans的,
所以如果是这样的情况的话:
now : 100110 1011
ans : 101100 0000
这样的话now < ans,所以now - ans 一定小于 2^(k-1),-1是因为第k位对应的是2^(k-1),几次方是从0开始数的
但是这样是不合法的,之所以这样会被误判为合法,是因为它之前的那个粗体0帮后面的粗体1抵消掉了。
因此为了这样的0不会对真正不合法的1造成干扰,
我们只需要计算(now | ans) - ans < 2^(k-1)是否成立即可,
因为这样的话,所有这样的0都会变为1,于是这时要再有不合法的1出现就无法被抵消了。
于是小数据就解决了,但是考虑到最大的点n <= 2000,这样的复杂度肯定是过不去的
但是观察发现,对于最大的那几个点,满足A == 1,
而之前的f数组之所以要开二维,还要枚举段数,就是因为只有枚举了所有情况才能保证不漏掉A~B之间的答案,
因为段数小不一定更优,不然可能会找到小于A的答案,
但是因为A == 1,就不可能会找到小于A的答案了,这时也满足段数小的一定更优,
所以我们直接令g[i]表示dp到i,使第k位为0的最小段数,
然后转移时判断条件和上面一样即可,注意初始化g[0]=0,其余为极大值
下面放代码:
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 2100
#define getchar() *o++
#define LL long long
char READ[],*o=READ;
int n,A,B,all;
int s[AC],g[AC];
LL sum[AC];//g[i]是适用于没有下限的情况
LL ans;
bool f[AC][]; inline int read()
{
int x=;char c=getchar();
while(c > '' || c < '') c=getchar();
while(c >= '' && c <= '') x=x*+c-'',c=getchar();
return x;
} void work1()//f[i][j]代表前i位分成j段,第k位能否在保证前k位都不变且不考虑后面all-k位的情况下是否可能与当前ans相同(此时第k位默认为0)
{//这样的话相当于给了一个判断依据ans,于是就可以提高复杂度以解决问题
LL now;//获取最高位数
bool done=false;
all=log2(sum[n]) + ;
for(R k=all; k ;k--)//枚举位数(从高位开始贪心)
{
memset(f,,sizeof(f));
f[][]=true;
done=false;//error!!!每次都要重置
for(R i=;i<=n;i++)//枚举到了哪里
{
int be=min(i,B);
for(R j=;j<=be;j++)//枚举分的段数
{
for(R l=j-;l<i;l++)//枚举上一段的结尾,error!!!上一段啊怎么可以等于。。。。
{
if(!f[l][j-]) continue;//因为是|,所以前面有1不能消掉,所以前面不满足就不能取了
now=sum[i] - sum[l];//获取区间和
if(((now | ans) - ans) < (1LL<<(k-)))//error!!!注意longlong
{//如果相差小于当前位,代表不一样的都在后面,就没关系了
f[i][j]=true;
break;
}
}
if(i == n)
{
if(j >= A && j <= B && f[i][j])
{
done=true;
break;//如果找到了就无需再找了
}
}
}
}
if(!done) ans+=1LL<<(k-);//因为1已经有一位了,所以只要移动k-1位就可以了(其实是因为本来就只要判断2^(k-1),因为第一位对应的是2^0)
}
printf("%lld\n",ans);
}
//g[i]代表满足这位为0最少需要的段数
void work2()
{
LL now;
all=log2(sum[n]) + ;
for(R k=all; k ;k--)
{
memset(g,,sizeof(g));
g[]=;
for(R i=;i<=n;i++)//枚举树
{
for(R j=;j<i;j++)//枚举上一段的结尾,,,懒得特判1了,就从0开始吧
{
now=sum[i] - sum[j];
if(((now | ans) - ans) < (1LL<<(k-))) g[i]=min(g[i],g[j]+);//error!!!注意longlong
}//因为要求最小的,所以就不能跳过了
}
/* printf("!!!%d:\n",k);
for(int i=1;i<=n;i++) printf("%d ",g[i]);
printf("\n");*/
if(g[n] > B) ans+=1LL<<(k-);//error!!!貌似在这里也要加LL吧
}
printf("%lld\n",ans);
} void pre()
{
n=read(),A=read(),B=read();
for(R i=;i<=n;i++) s[i]=read(),sum[i]=sum[i-] + (LL)s[i];
} int main()
{
freopen("in.in","r",stdin);
// freopen("sculpture.in","r",stdin);
// freopen("sculpture.out","w",stdout);
fread(READ,,,stdin);
pre();
if(A == ) work2();//特殊点特殊处理
else work1();
fclose(stdin);
// fclose(stdout);
return ;
}
[APIO2015]巴厘岛的雕塑 贪心+DP+特殊数据优化的更多相关文章
- [APIO2015]巴厘岛的雕塑 --- 贪心 + 枚举
[APIO2015]巴厘岛的雕塑 题目描述 印尼巴厘岛的公路上有许多的雕塑,我们来关注它的一条主干道. 在这条主干道上一共有\(N\)座雕塑,为方便起见,我们把这些雕塑从 1 到\(N\)连续地进行 ...
- 【BZOJ4069】【APIO2015】巴厘岛的雕塑 [贪心][DP]
巴厘岛的雕塑 Time Limit: 10 Sec Memory Limit: 64 MB[Submit][Status][Discuss] Description 印尼巴厘岛的公路上有许多的雕塑, ...
- bzoj 4069: [Apio2015]巴厘岛的雕塑【dp】
居然要对不同的数据写不同的dp= = 首先记得开long long,<<的时候要写成1ll<<bt 根据or的性质,总体思路是从大到小枚举答案的每一位,看是否能为0. 首先对于 ...
- BZOJ 4069 [Apio2015]巴厘岛的雕塑 ——贪心
自己首先想了一种方法$f(i)$表示前$i$个最小值为多少. 然而发现位运算并不满足局部最优性. 然后我们可以从高到低贪心的判断,使得每一组的和在一个特定的范围之内. 还要特判最后一个Subtask, ...
- APIO2015巴厘岛的雕塑——数位DP
题目:https://www.luogu.org/problemnew/show/P3646 对于A>1,将答案各位全置1,然后从高位到低位改成0判断是否可行: 用f[i][j]数组代表前i个数 ...
- 【BZOJ4069】[Apio2015]巴厘岛的雕塑 按位贪心+DP
[BZOJ4069][Apio2015]巴厘岛的雕塑 Description 印尼巴厘岛的公路上有许多的雕塑,我们来关注它的一条主干道. 在这条主干道上一共有 N 座雕塑,为方便起见,我们把这些雕塑从 ...
- bzoj 4069 [Apio2015]巴厘岛的雕塑 dp
[Apio2015]巴厘岛的雕塑 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 494 Solved: 238[Submit][Status][Dis ...
- bzoj千题计划239:bzoj4069: [Apio2015]巴厘岛的雕塑
http://www.lydsy.com/JudgeOnline/problem.php?id=4069 a!=1: 从高位到低位一位一位的算 记录下哪些位必须为0 dp[i][j] 表示前i个数分为 ...
- [APIO2015]巴厘岛的雕塑[按位贪心+dp]
题意 给你长度为 \(n\) 的序列,要求分成 \(k\) 段连续非空的区间,求所有区间和的 \(or\) 最小值. 分析 定义 \(f_{i,j}\) 表示前 \(i\) 个点分成 \(j\) 段的 ...
随机推荐
- 蓝牙入门知识-CC2541知识
蓝牙是为了能够通信,想要通信就必须遵守一定的规则, Profile 就可以理解为相互约定的规则,因为每个协议栈demo 都会有一个Profile 与之对应, 我们这里的SimpleBLExxx 对应的 ...
- 第十五届北京师范大学程序设计竞赛现场决赛题解&源码(A.思维,C,模拟,水,坑,E,几何,思维,K,字符串处理)
#include <bits/stdc++.h> using namespace std; int main() { int T,n,a,b; while(cin>>T) { ...
- 第七模块:项目实战一 第1章 项目实战:CRM客户关系管理系统开发
01-crm介绍 02-权限系统介绍 03-第一版表结构设计 04-第二版表结构设计 05-orm中创建表结构 06-销售管理系统业务 07-销售管理系统权限信息录入 08-快速实现简单的权限控制的设 ...
- 新的征程 in ZJU
争取考上了心仪的学校 并进入了心仪的实验室 但是对我来说,未来将是更多的挑战 首先我觉得我学习能力还是不足,无法做到一天的高效率学习 实验室的方向是可视化,我觉得这个是个非常复杂的方向 数学,pyth ...
- Stunnel客户端安装和配置
声明:本文并非原创,转自华为云帮助中心的分布式缓存服务(DCS)的用户指南. 本文以公网访问华为云分布式缓存服务的Redis缓存为示例,介绍Stunnel客户端在各操作系统下的安装和配置. Stunn ...
- 78[LeetCode] Subsets
Given a set of distinct integers, nums, return all possible subsets (the power set). Note: The solut ...
- 2018java开发一些面经
算法系列:https://www.cnblogs.com/yanmk/p/9232908.html 2018Java开发面经(持续更新) 不要给自己挖坑!!!不要给自己挖坑!!!不要给自己挖坑!!!如 ...
- OpenCV学习4-----K-Nearest Neighbors(KNN)demo
最近用到KNN方法,学习一下OpenCV给出的demo. demo大意是随机生成两团二维空间中的点,然后在500*500的二维空间平面上,计算每一个点属于哪一个类,然后用红色和绿色显示出来每一个点 如 ...
- BZOJ 4361 isn 容斥+dp+树状数组
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4361 题意概述: 给出一个长度为N的序列A(A1,A2...AN).如果序列A不是非降的 ...
- Cannot retrieve repository metadata (repomd.xml) for repository: base. Please verify its path and try again YUM报错
1.挂盘 ----- 2.# mount /dev/sr0 /media/ mount: block device /dev/sr0 is write-protected, mounting ...