51Nod1376 (dp + BIT // cdq分治)

https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1376

求LIS的数量。

乍一看觉得还是dp,仔细一看确实可以用dp做。

显而易见的是一个O(n2)的dp,同时维护LIS的值和cnt的数量 当然,由于数据限制,考虑优化

我们看了题解冷静分析之后想到了用树状数组优化。

用一个结构体node来存储len和cnt两个关键信息,重载他们之间的+运算符

struct Node{
    LL cnt,len;
    Node(){}
    Node(int len,int cnt):len(len),cnt(cnt) {}
    Node operator + (Node t){
        if(t.len > this->len){
            return t;
        }else if(t.len < this->len){
            return (*this);
        }else{
            return Node(t.len,(t.cnt + this->cnt) % mod);
        }
    }
}node[maxn];
View Code

看起来就很帅,实际上这是一个偏向比较的运算符,两个node之间长度不相等的就取长度较大的,长度相等就将两个cnt加起来。

我们将所有的数从大到小排序,并且大小相同时编号后面的靠前,保证在遍历每个数时树状数组里所有的数都可以当作他的前缀最大值。直接上dp递推即可。

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
const int MAXBUF=10000;char buf[MAXBUF],*ps=buf,*pe=buf+1;
inline bool isdigit(const char& n) {return (n>='0'&&n<='9');}
inline void rnext(){if(++ps==pe)pe=(ps=buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin);}
template <class T> inline bool in(T &ans){
#ifdef VSCode
ans=0;T f=1;register char c;
do{c=getchar();if ('-'==c)f=-1;}while(!isdigit(c)&&c!=EOF);
if(c==EOF)return false;do{ans=(ans<<1)+(ans<<3)+c-48;
c=getchar();}while(isdigit(c)&&c!=EOF);ans*=f;return true;
#endif
#ifndef VSCode 
ans =0;T f=1;if(ps==pe)return false;do{rnext();if('-'==*ps)f=-1;} 
while(!isdigit(*ps)&&ps!=pe);if(ps==pe)return false;do{ans=(ans<<1)+(ans<<3)+*ps-48;
rnext();}while(isdigit(*ps)&&ps!=pe);ans*=f;return true;
#endif
}const int MAXOUT=10000;   //*(int(*)[10])p
char bufout[MAXOUT], outtmp[50],*pout = bufout, *pend = bufout+MAXOUT;
inline void write(){fwrite(bufout,sizeof(char),pout-bufout,stdout);pout = bufout;}
inline void out_char(char c){*(pout++)=c;if(pout==pend)write();}
inline void out_str(char *s){while(*s){*(pout++)=*(s++);if(pout==pend)write();}}
template <class T>inline void out_int(T x) {if(!x){out_char('0');return;}
if(x<0)x=-x,out_char('-');int len=0;while(x){outtmp[len++]=x%10+48;x/=10;}outtmp[len]=0;
for(int i=0,j=len-1;i<j;i++,j--) swap(outtmp[i],outtmp[j]);out_str(outtmp);}
template<typename T, typename... T2>
inline int in(T& value, T2&... value2) { in(value); return in(value2...); }
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Scl(x) scanf("%lld",&x);  
#define Pri(x) printf("%d
", x)
#define Prl(x) printf("%lld
",x);  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
#define Vec Point
typedef vector<int> VI;
const double eps = 1e-9;
const int maxn = 5e4 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,tmp,K;
PII a[maxn];
struct Node{
    LL len,cnt;
    Node(){}
    Node(LL len,LL cnt):len(len),cnt(cnt){}
    Node operator + (const Node &t){
        if(this->len < t.len){
            return t;
        }
        if(this->len > t.len){
            return (*this);
        }
        return Node(t.len,(this->cnt + t.cnt) % mod);
    }
}tree[maxn];
int lowbit(int t){
    return t & (-t);
}
void update(int t,Node x){
    while(t <= N){
        tree[t] = tree[t] + x;
        t += lowbit(t);
    }
}
Node query(int t){
    Node s = Node(0,0);
    while(t > 0){
        s = s + tree[t];
        t -= lowbit(t);
    }
    return s;
}
bool cmp(PII a,PII b){
    if(a.fi != b.fi) return a.fi < b.fi;
    return a.se > b.se;
}
int main()
{
    in(N);
    For(i,1,N) in(a[i].fi),a[i].se = i;
    sort(a + 1,a + 1 + N,cmp);
    Node ans(0,0);
    For(i,1,N){
        Node t = query(a[i].se - 1);
        if(++t.len == 1) t.cnt = 1;
        t.len %= mod;
        ans  = ans + t;
        update(a[i].se,t);
    }
    Prl(ans.cnt);
    #ifdef VSCode
    write();
    system("pause");
    #endif
    return 0;
}
View Code

这题也可以变成一个二维偏序问题,寻找一个在len长度最大情况下的cnt,用cdq分治解决。

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
const int MAXBUF=10000;char buf[MAXBUF],*ps=buf,*pe=buf+1;
inline bool isdigit(const char& n) {return (n>='0'&&n<='9');}
inline void rnext(){if(++ps==pe)pe=(ps=buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin);}
template <class T> inline bool in(T &ans){
#ifdef VSCode
ans=0;T f=1;register char c;
do{c=getchar();if ('-'==c)f=-1;}while(!isdigit(c)&&c!=EOF);
if(c==EOF)return false;do{ans=(ans<<1)+(ans<<3)+c-48;
c=getchar();}while(isdigit(c)&&c!=EOF);ans*=f;return true;
#endif
#ifndef VSCode 
ans =0;T f=1;if(ps==pe)return false;do{rnext();if('-'==*ps)f=-1;} 
while(!isdigit(*ps)&&ps!=pe);if(ps==pe)return false;do{ans=(ans<<1)+(ans<<3)+*ps-48;
rnext();}while(isdigit(*ps)&&ps!=pe);ans*=f;return true;
#endif
}const int MAXOUT=10000;   //*(int(*)[10])p
char bufout[MAXOUT], outtmp[50],*pout = bufout, *pend = bufout+MAXOUT;
inline void write(){fwrite(bufout,sizeof(char),pout-bufout,stdout);pout = bufout;}
inline void out_char(char c){*(pout++)=c;if(pout==pend)write();}
inline void out_str(char *s){while(*s){*(pout++)=*(s++);if(pout==pend)write();}}
template <class T>inline void out_int(T x) {if(!x){out_char('0');return;}
if(x<0)x=-x,out_char('-');int len=0;while(x){outtmp[len++]=x%10+48;x/=10;}outtmp[len]=0;
for(int i=0,j=len-1;i<j;i++,j--) swap(outtmp[i],outtmp[j]);out_str(outtmp);}
template<typename T, typename... T2>
inline int in(T& value, T2&... value2) { in(value); return in(value2...); }
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Scl(x) scanf("%lld",&x);  
#define Pri(x) printf("%d
", x)
#define Prl(x) printf("%lld
",x);  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
#define Vec Point
typedef vector<int> VI;
const double eps = 1e-9;
const int maxn = 5e4 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,tmp,K; 
int a[maxn];
struct Node{
    LL cnt,len;
    Node(){}
    Node(int len,int cnt):len(len),cnt(cnt) {}
    Node operator + (Node t){
        if(t.len > this->len){
            return t;
        }else if(t.len < this->len){
            return (*this);
        }else{
            return Node(t.len,(t.cnt + this->cnt) % mod);
        }
    }
}node[maxn];
int id[maxn];
bool cmp(int x,int y){
    if(a[x] == a[y]) return x > y;
    return a[x] < a[y];
}
void cdq(int l,int r){
    if(l == r) return;
    int m = l + r >> 1;
    cdq(l,m);
    For(i,l,r) id[i] = i;
    sort(id + l,id + r + 1,cmp);
    Node MAX = Node(0,0); 
    For(i,l,r){
        int idx = id[i];
        if(idx <= m){
            MAX = MAX + node[idx];
        }else{
            Node t = MAX;
            t.len++;
            node[idx] = node[idx] + t;
        }
    }
    cdq(m + 1,r);
}
int main()
{
    in(N);
    For(i,1,N) in(a[i]);
    For(i,1,N) node[i] = Node(1,1);
    cdq(1,N);
    Node MAX = Node(0,0);
    For(i,1,N) MAX = MAX + node[i];
    Prl(MAX.cnt);
    #ifdef VSCode
    write();
    system("pause");
    #endif
    return 0;
}
原文地址:https://www.cnblogs.com/Hugh-Locke/p/9499738.html