[POJ 3378] Crazy Thairs

Link:

POJ 3378 传送门

Solution:

按序列长度$dp$,

设$dp[i][j]$为到第$i$个数,符合要求的序列长度为$j$时的序列个数,

易得转移方程:$dp[i][j]=\sum_{k=1}^{i-1} dp[k][j-1] (dat[k]<dat[i])$

用树状数组按$dat[i]$为坐标来维护$dp[i][j-1]$的值即可,

由于$dat[i] \le 1e9$,记得离散化,同时答案超过$long long$,要高精度

这里可以选择开5个树状数组,也可以只用一个树桩数组,每次维护$dp[][j-1]$的值后清空

由于此题卡空间,推荐我用的第二种

如果要用第一种,要用到高精度的一些黑科技,改为10000进制,这样只要7位就行了Orz

10000进制的输出:

void Print() 
{
    if(len==0) {puts("0");return;}
    printf("%d", num[len - 1]);
    for(int i=len-2;i>=0;--i) 
        for(int j=Base/10;j>0;j/=10) 
            printf("%d", num[i]/j%10);
    puts("");
}

Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>

using namespace std;
const int MAXN=5e4+10;
int T,dsp[MAXN],n,dat[MAXN],tot=0;

struct BI //高精度类
{
    int d[25],len;
    
    BI() {memset(d,0,sizeof(d));len=1;}
    void clean(){memset(d,0,sizeof(d)),len=1;}
    BI(int num) {*this=num;}
    
    BI& operator = (const int& num)
    {
        memset(d,0,sizeof(d));
        int temp=num;len=0;
        while(temp)
            d[++len]=temp%10,temp/=10;
        return *this;
    }
    
    BI operator + (const BI& num)
    {
        BI ret;ret=*this;
        ret.len=max(len,num.len);
        for(int i=1;i<=ret.len;i++)
        {
            ret.d[i]+=num.d[i];
            if(ret.d[i]>=10)
                ret.d[i]-=10,ret.d[i+1]++;
        }
        if(ret.d[ret.len+1]) ret.len++;
        return ret;
    }
    BI operator += (const BI& num){*this=*this+num;return *this;}
    void print(){for(int i=len;i>=1;i--) printf("%d",d[i]);}
}bit[MAXN],dp[MAXN][6],res;

void Update(int pos,BI val){while(pos<=n) bit[pos]+=val,pos+=pos&(-pos);}
BI Query(int pos)
{
    BI ret=0; //记得初始化
    while(pos) ret+=bit[pos],pos-=pos&(-pos);
    return ret;
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++) scanf("%d",&dat[i]),dsp[i]=dat[i]; //离散化
        sort(dsp+1,dsp+n+1);tot=unique(dsp+1,dsp+n+1)-dsp-1;
        for(int i=1;i<=n;i++) dat[i]=lower_bound(dsp+1,dsp+tot+1,dat[i])-dsp;
        
        res.clean();
        for(int i=0;i<n+5;i++) for(int j=0;j<6;j++) dp[i][j].clean();
        for(int i=1;i<=n;i++) dp[i][1]=(BI)1;
        for(int i=2;i<=5;i++)
        {
            for(int j=0;j<tot+5;j++) bit[j].clean();
            for(int j=1;j<=n;j++)
                dp[j][i]=Query(dat[j]-1),Update(dat[j],dp[j][i-1]);
        }
        for(int i=1;i<=n;i++) res+=dp[i][5];
        res.print();puts("");
    }
    return 0;
}

Review:

一道比较常规的题吧,用到了离散化和高精度的一些套路

(1)如果$dp$复杂度有问题,可以向单调性/斜率优化/RMQ维护上想一想

(2)犯的丝帛错误:

$Query$函数里的$ret$要预处理!!!

(3)黑科技:高精度空间不够时转为更高进制(10000进制) 

猜你喜欢

转载自www.cnblogs.com/newera/p/9157322.html