题解【bzoj3688 折线统计】

考虑 \(dp\) 。

首先把所有节点按 \(x\) 从小到大排序是很有必要的。

f[i][j][0] 表示满足以第 \(i\) 个节点做折线结尾,选取的点集 \(S\) 满足 \(f(S)=j\) ,且最后一段折线指向右上 \(()\) 的方案数。

f[i][j][1] 表示满足以第 \(i\) 个节点做折线结尾,选取的点集 \(S\) 满足 \(f(S)=j\) ,且最后一段折线指向右下 \(()\) 的方案数 。

状态转移方程:(我觉得挺显然的,感性理解一下就行了
\[
f[i][j][0]=\sum\limits_{i'<i \ \& \ y[i']<y[i]} f[i'][j][0]+\sum\limits_{i'<i \ \& \ y[i']<y[i]} f[i'][j-1][1]
\]

\[
f[i][j][1]=\sum\limits_{i'<i \ \& \ y[i']>y[i]} f[i'][j][1] + \sum\limits_{i'<i \ \& \ y[i']>y[i]} f[i'][j-1][0]
\]

答案即为 \(\sum f[i][k][0]+\sum f[i][k][1]\) 。

然后我们发现直接这样做 \(dp\) 是 \(Θ(n^2k)\) 的。

\(...\)

其实我们可以发现:

这个 \(i'<i\) 的限制按照 \(x\) 从小到大扫描的顺序就可以解决。

这个 \(y[i']<y[i]\) 以及 \(y[i']>y[i]\) 的限制可以用一个数据结构(线段树 \(/\) 树状数组)优化成 \(\log\) 。

时间复杂度 \(Θ(n \ k \log n)\) 。


Code 部分

#include<cstdio>
#include<algorithm>

#define RI register int

using namespace std;

inline int read()
{
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}

const int SIZE=50010,M=21,MAXV=100000;

const int mod=1e5+7;

void faq()
{
    puts("nmsl");
}

int n,m;

struct Node{
    int x,y;
}a[SIZE];

int cmp(Node a,Node b)
{
    return a.x<b.x;
}

int c[M][MAXV+100][2];

void add(int d1,int x,int d2,int val)
{
    for(;x<=MAXV;x+=x&-x)c[d1][x][d2]=(c[d1][x][d2]+val)%mod;
}

int ask(int d1,int d2,int x)
{
    int ans=0;
    for(;x;x-=x&-x)ans=(ans+c[d1][x][d2])%mod;
    return ans;
}

int query(int d1,int d2,int l,int r)
{
    if(l>r)return 0;
    int ans=ask(d1,d2,r)-ask(d1,d2,l-1);
    ans+=mod;
    ans%=mod;
    return ans;
}

int f[SIZE][M][2];

int main()
{
    n=read(),m=read();

    for(RI i=1;i<=n;i++)
        a[i].x=read(),a[i].y=read();

    sort(a+1,a+1+n,cmp);

    add(0,a[1].y,0,1);
    add(0,a[1].y,1,1);

    for(RI i=2;i<=n;i++)
    {
        f[i][0][0]=f[i][0][1]=1;
        for(RI j=1;j<=m;j++)
            f[i][j][0]=(query(j,0,1,a[i].y-1)+query(j-1,1,1,a[i].y-1))%mod,
            f[i][j][1]=(query(j,1,a[i].y+1,MAXV)+query(j-1,0,a[i].y+1,MAXV))%mod;
        for(RI j=0;j<=m;j++)
            add(j,a[i].y,0,f[i][j][0]),add(j,a[i].y,1,f[i][j][1]);
    }

    printf("%d\n",(ask(m,0,MAXV)+ask(m,1,MAXV))%mod);

    return 0;
}


\[
thanks \ for \ watching
\]

原文地址:https://www.cnblogs.com/cjtcalc/p/12216589.html

时间: 2024-10-09 01:39:25

题解【bzoj3688 折线统计】的相关文章

BZOJ3688: 折线统计

题解: 令f[i][j][0/1]表示前i个数有j段,最后一段是下降/上升的方案数 很容易列出状态转移方程(已按x轴排序) f[i][j][0]=sigma(f[k][j][0]+f[k][j-1][1])(k<i&&a[k]>a[i]) f[i][j][1]=sigma(f[k][j][1]+f[k][j-1][1])(k<i&&a[k]<a[i]) 很明显可以用树状数组优化. 代码: 1 #include<cstdio> 2 #inc

动态规划 BZOJ3688 折线统计

3688: 折线统计 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 234  Solved: 118[Submit][Status][Discuss] Description 二维平面上有n个点(xi, yi),现在这些点中取若干点构成一个集合S,对它们按照x坐标排序,顺次连接,将会构成一些连续上升.下降的折线,设其数量为f(S).如下图中,1->2,2->3,3->5,5->6(数字为下图中从左到右的点编号),将折线分为了4部分,

BZOJ3688折线统计 dp+线段树

Description 二 维平面上有n个点(xi, yi),现在这些点中取若干点构成一个集合S,对它们按照x坐标排序,顺次连接,将会构成一些连续上升.下降的折线,设其数量为f(S).如下图 中,1->2,2->3,3->5,5->6(数字为下图中从左到右的点编号),将折线分为了4部分,每部分连续上升.下降.   现给定k,求满足f(S) = k的S集合个数. Input 第一行两个整数n和k,以下n行每行两个数(xi, yi)表示第i个点的坐标.所有点的坐标值都在[1, 1000

[FJSC2014]折线统计

[题目描述] 二维平面上有n 个点(xi, yi),现在这些点中取若干点构成一个集合S,对它们按照x 坐标排序,顺次连接,将会构成一些连续上升.下降的折线,设其数量为f(S).如下图中,1->2,2->3,3->5,5->6(数字为下图中从左到右的点编号),将折线分为了4 部分,每部分连续上升.下降. 现给定k,求满足f(S) = k 的S 集合个数. [输入格式] 第一行两个整数n 和k,以下n 行每行两个数(xi, yi)表示第i 个点的坐标. 所有点的坐标值都在[1, 100

BZOJ 3688 折线统计

dp[i][j][0/1]一下,然后发现可以BIT搞.注意外层for所有点. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 50050 #define mod 100007 using namespace std; int n,k,f[maxn][12][2],t[maxn<<1][12][2],mx=0; struct

K:剑指offer-56 题解 谁说数字电路的知识不能用到算法中?从次数统计到逻辑表达式的推导,一文包你全懂

前言: 本题解整理了一位大佬在leetcode中的代码的方法,该博文致力于让所有人都能够能够看懂该方法.为此,本题解将从统计数字出现次数的解题方式开始讲起,再推导出逐位统计的解题方式,期望以循序渐进的方式得出最终代码的思想. 相关知识关键字: 二进制.位运算.真值表.逻辑表达式.状态机 题目: 剑指offer 56 II. 数组中数字出现的次数 II 在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次.请找出那个只出现一次的数字. 示例 1: 输入:nums = [3,4,3

某模拟赛C题 树上路径统计 (点分治)

题意 给定一棵有n个节点的无根树,树上的每个点有一个非负整数点权.定义一条路径的价值为路径上的点权和-路径上的点权最大值. 给定参数P,我!=们想知道,有多少不同的树上简单路径,满足它的价值恰好是P的倍数. 注意:单点算作一条路径:u!=v时,(u,v)和(v,u)只算一次. 题解 树上路径统计,解法是点分治.点分的时候求出根到每个点路径最大值和权值和.排一序,然后开个桶,就能计算了.去重就套路的减去没棵子树里面的答案. CODE #include <bits/stdc++.h> using

Leetcode-387 First Unique Character in a String

#387.   First Unique Character in a String Given a string, find the first non-repeating character in it and return it's index. If it doesn't exist, return -1. Examples: s = "leetcode" return 0. s = "loveleetcode", return 2. Note: You m

echarts图表变形解决方案

在同一页面的多个echarts图在查询或切换图片时可能会变形,如图 解决方案是添加以下几行代码 /*在查询或切换统计图时图片有可能会变形,于是每次调getEchartsData()都给每个chart的宽度定义成初始值*/ $("#myChart2").css( 'width', $("#myChart2").width()); $("#myChart3").css( 'width', $("#myChart3").width(