BZOJ4282 : 慎二的随机数列

首先在开头加上-inf,结尾加上inf,最后答案减2即可。

设s[i]为i之前未知的个数,f[i]为以i结尾的LIS,且a[i]已知,那么:

f[i]=max(f[j]+min(s[i]-s[j],a[i]-a[j]-1))+1,其中j<i,a[j]<a[i]且a[j]已知

将min分类讨论后可转化为三维偏序,CDQ分治+扫描线+树状数组即可,时间复杂度$O(n\log^2n)$。

#include<cstdio>
#include<algorithm>
using std::sort;
const int N=100010,inf=1000000000;
char ch[5];
int n,m,i,a[N],s[N],b[N],c[N],B[N],C[N<<1],f[N],g[N];
int qa[N],qb[N],ca,cb,T,pos0[N],bit0[N],pos1[N<<1],bit1[N<<1];
inline int cmp(int x,int y){return a[x]<a[y];}
inline int lowerb(int x){
  int l=1,r=m,mid,t;
  while(l<=r)if(B[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1;
  return t;
}
inline int lowerc(int x){
  int l=1,r=n,mid,t;
  while(l<=r)if(C[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1;
  return t;
}
inline void up(int&a,int b){if(a<b)a=b;}
inline void add0(int x,int y){for(;x<=m;x+=x&-x)if(pos0[x]<T)pos0[x]=T,bit0[x]=y;else up(bit0[x],y);}
inline void ask0(int&t,int x){for(;x;x-=x&-x)if(pos0[x]==T)up(t,bit0[x]);}
inline void add1(int x,int y){for(;x<=n;x+=x&-x)if(pos1[x]<T)pos1[x]=T,bit1[x]=y;else up(bit1[x],y);}
inline void ask1(int&t,int x){for(;x;x-=x&-x)if(pos1[x]==T)up(t,bit1[x]);}
void solve(int l,int r){
  if(l==r){
    f[l]+=s[l]+1,g[l]+=a[l];
    if(l==1)f[l]=1;
    up(f[l],g[l]);
    return;
  }
  int mid=(l+r)>>1;
  solve(l,mid);
  int i,j;
  ca=cb=0;
  for(i=l;i<=mid;i++)qa[ca++]=i;
  for(i=r;i>mid;i--)qb[cb++]=i;
  sort(qa,qa+ca,cmp),sort(qb,qb+cb,cmp);
  for(T++,i=j=0;i<cb;i++){
    while(j<ca&&a[qa[j]]<a[qb[i]]){
      add0(b[qa[j]],f[qa[j]]-s[qa[j]]);
      add1(lowerc(c[qa[j]]-1),f[qa[j]]-a[qa[j]]);
      j++;
    }
    ask0(f[qb[i]],b[qb[i]]-1);
    ask1(g[qb[i]],lowerc(c[qb[i]]));
  }
  solve(mid+1,r);
}
int main(){
  scanf("%d",&n);
  a[m=1]=-inf;
  while(n--){
    scanf("%s",ch);
    if(ch[0]==‘N‘)i++;else s[++m]=i,scanf("%d",&a[m]);
  }
  s[++m]=i,a[m]=inf;
  for(n=0,i=1;i<=m;i++){
    B[i]=b[i]=a[i]-s[i];
    C[++n]=c[i]=s[i]-a[i];
    C[++n]=c[i]-1;
    f[i]=g[i]=-inf;
  }
  sort(B+1,B+m+1),sort(C+1,C+n+1);
  for(i=1;i<=m;i++)b[i]=lowerb(b[i]);
  solve(1,m);
  return printf("%d",f[m]-2),0;
}

  

时间: 2024-12-23 00:26:16

BZOJ4282 : 慎二的随机数列的相关文章

[bzoj4282]慎二的随机数列_动态规划_贪心

慎二的随机数列 bzoj-4282 题目大意:一个序列,序列上有一些数是给定的,而有一些位置上的数可以任意选择.问最长上升子序列. 注释:$1\le n\le 10^5$. 想法:结论:逢N必选.N是可以任意选择的位置. 具体的,我们将所有N踢出序列,将给定的权值-=前面N的个数.再在当前序列上求最长上升子序列. 正确性的话如果当前序列中的数: 如果前面的数小于后面的数,显然中间的N我也可以加上. 如果前面的数大于后面的数: 如果前面的数在原序列中的权值大于后面的数在原序列中的权值,那么这两个数

【bzoj4282】慎二的随机数列

扯几句题外的,最近在看Fate/StayNight,对此人毫无好感-- 每次减一下当前可辨认数,然后随意dp一个LIS,最后记得加回去就好. 1 #include<bits/stdc++.h> 2 #define N 100010 3 using namespace std; 4 int q[N],s[N],dp[N],sum,n,top,t,x; 5 int main(){ 6 scanf("%d",&n); 7 for(int i=1;i<=n;i++){

关于随机数列,对给定数目的自0开始步长为1的数字序列进行乱序。(可用作洗牌)

1 /** 2  * 数组乱序类 3  * @author noam  4  */ 5 public class NRandom { 6  7     /** 8      * 对给定数目的自0开始步长为1的数字序列进行乱序 9      * @param no 给定数目10      * @return 乱序后的数组11      */12     public static int[] getSequence(int no) {13         int[] sequence = new 

在lua中 获取1到n的随机数列

之前工作上有一个方法经常用到,就是获取1到n的一个随机数列,数列中不能有重复的数字,也就是1,2,3,4,5 生成2,1,3,4,5或者5,4,3,2,1这样的随机队列. 这里我就把自己的lua实现贴在这里以供以后参考:感觉这个方法效率还是不错的. function getRandomList(length) local temp = {} local chosen_list = {} for i = 1, length do table.insert(chosen_list, i) end f

不重复随机数列生成

问题描述: 随机生成k个不重复的随机数(或生成0至k-1以随机顺序构成的数列) 算法: rand不直接产生值,而是产生下标,下标可以重复,但要保证数组中都是不重复且没有输出过的数字 ①一个大小为k的数组temp,temp[i]=i:一个随机下标的范围range,range初始为k:一个随机数组result ②随机生成0至range-1的一个下标index,将temp[index]放入result ③temp[index]=temp[range-1] ④range--,转② 代码: #pragma

用随机数列模拟抛硬币

先粘贴上代码 package djbc; import java.util.Random;import java.util.Scanner; public class Lian {public static void main(String[] args) {int i=0,k=0,t=0;  System.out.println("请输入要抛的次数");Scanner scan=new Scanner(System.in);//输入抛硬币的次数t=scan.nextInt();Ran

自动生成二年级随机四则运算的系统

主要公式为:VLOOKUP.RANDBETWEEN 1.VLOOKUP函数是Excel中的一个纵向查找函数, 功能:按列查找,最终返回该列所需查询列序所对应的值: 具体使用方法为:VLOOKUP(要查找的值,要查找的区域,返回数据在查找区域的第几列数,模糊匹配/精确匹配(TRUE/FALSE或者不填)) 2.RANDBETWEEN作用为返回位于两个指定数之间的一个随机整数. 每次计算工作表时都将返回一个新的随机整数. 使用方法: RANDBETWEEN(bottom,top) Bottom参数:

排序算法总结二

本文接排序算法总结一 3. 冒泡排序 冒泡排序的基本思想:以正序排列为例,我们首先要将最大的数沉到最底下,从第一个数开始,比较相邻的两个数,如果为逆序则交换这两个数,重复这个操作直到倒数第二个数,此时最大的数已沉到最底下:然后再从第一个数开始,用同样的方法将次大的数沉到次底下,重复这个过程直到排序成功.代码如下: void PaoSort1(vector<int>& a) { int length = a.size(); for (int i = 0; i < length -

解密随机数生成器(二)——从java源码看线性同余算法

Random Java中的Random类生成的是伪随机数,使用的是48-bit的种子,然后调用一个linear congruential formula线性同余方程(Donald Knuth的编程艺术的3.2.1节) 如果两个Random实例使用相同的种子,并且调用同样的函数,那么生成的sequence是相同的 也可以调用Math.random()生成随机数 Random实例是线程安全的,但是并发使用Random实例会影响效率,可以考虑使用ThreadLocalRandom变量. Random实