zoukankan      html  css  js  c++  java
  • HDU 4352 XHXJ's LIS

    题目

    题意:定义一个数字的LIS为将其看成一个字符串的LIS,问([l,r])内有多少数字的LIS长度为(k)

    考虑树状数组求一个序列LIS的过程,我们定义了一个东西(f_i)表示结尾元素不超过(i)的LIS的最大长度,维护这个数组就能实现较为快速的转移

    显然这个数组是单调不降的,且不难发现(f_i-f_{i-1}leq 1),于是差分之后就只会存在(0,1)两种元素

    于是我们在数位dp的过程中把差分序列记下来作为dp的状态就好了,注意前导零的问题,以及预处理转移会更快

    代码

    #include<cstdio>
    #include<cstring>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    LL L,R;int k,m,lm[66];
    int id[(1<<10)+5],st[11][(1<<10)+5],cnt[(1<<10)+5];
    LL dp[2][(1<<10)+5][2];
    int A[(1<<10)+5][11],tr[(1<<10)+5][11],B[11],M[11];
    inline void trans(int state) {
    	for(re int i=0;i<10;++i)A[m][i]=state>>i&1;
    	for(re int i=1;i<10;++i)A[m][i]+=A[m][i-1]; 
    }
    inline void Pre_tr(int x) {
    	for(re int i=0;i<10;i++) {
    		for(re int j=0;j<10;j++)B[j]=A[x][j];
    		B[i]=max(B[i],(i>0?A[x][i-1]:0)+1);
    		for(re int j=1;j<10;j++)B[j]=max(B[j-1],B[j]);
    		tr[x][i]=B[0];
    		for(re int j=1;j<10;j++) tr[x][i]|=((B[j]-B[j-1])<<j);
    		tr[x][i]=id[tr[x][i]];
    	}
    }
    void dfs(int x,int state,int res) {
    	if(res<0) return;
    	if(x==10) {
    		id[state]=++m;trans(state);
    		cnt[m]=res;st[res][++M[res]]=m;
    		return;
    	}
    	dfs(x+1,state,res);
    	dfs(x+1,state|(1<<x),res+1);
    }
    inline LL calc(LL N) {
    	if(!N)return 0;int tot=0;
    	while(N) lm[++tot]=N%10ll,N/=10ll;
    	int o=0;memset(dp,0,sizeof(dp));
    	for(re int i=tot;i;--i,o^=1) {
    		dp[o][id[0]][i==tot?1:0]++;
    		for(re int j=1;j<=m;j++) dp[o^1][j][0]=dp[o^1][j][1]=0;
    		for(re int j=1;j<=m;j++) {
    			if(!dp[o][j][0]) continue;
    			if(cnt[j]>=k) continue;
    			for(re int k=0;k<10;++k)
    				if(tr[j][k]) dp[o^1][tr[j][k]][0]+=dp[o][j][0];
    		}
    		for(re int j=1;j<=m;j++) {
    			if(!dp[o][j][1]) continue;
    			if(cnt[j]>=k) continue;
    			for(re int k=0;k<lm[i];++k)
    				if(tr[j][k]) dp[o^1][tr[j][k]][0]+=dp[o][j][1];
    			if(tr[j][lm[i]]) dp[o^1][tr[j][lm[i]]][1]+=dp[o][j][1];
    		}
    		dp[o^1][tr[id[0]][0]][lm[i]?0:1]--;
    	}
    	LL ans=0;
    	for(re int i=1;i<=M[k];i++) ans+=dp[o][st[k][i]][0]+dp[o][st[k][i]][1];
    	return ans;
    }
    int main() {
    	m=0;dfs(0,0,0);
    	for(re int i=1;i<=m;i++) Pre_tr(i);
    	int T;scanf("%d",&T);
    	for(re int tnum=1;tnum<=T;++tnum) {
    		scanf("%lld%lld%d",&L,&R,&k);
    		printf("Case #%d: %lld
    ",tnum,calc(R)-calc(L-1));
    	}
    	return 0;
    }
    

    之后这玩意就T没了,原因是(Tleq 10^4),实在是不小;于是改成记忆化才行

    #include<cstdio>
    #include<cstring>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    LL L,R;int k,m,lm[66];
    int id[(1<<10)+5],cnt[(1<<10)+5];
    LL dp[20][(1<<10)+5][11];
    int A[(1<<10)+5][11],tr[(1<<10)+5][11],B[11],M[11];
    inline void trans(int state) {
    	for(re int i=0;i<10;++i)A[m][i]=state>>i&1;
    	for(re int i=1;i<10;++i)A[m][i]+=A[m][i-1]; 
    }
    inline void Pre_tr(int x) {
    	for(re int i=0;i<10;i++) {
    		for(re int j=0;j<10;j++)B[j]=A[x][j];
    		B[i]=max(B[i],(i>0?A[x][i-1]:0)+1);
    		for(re int j=1;j<10;j++)B[j]=max(B[j-1],B[j]);
    		tr[x][i]=B[0];
    		for(re int j=1;j<10;j++) tr[x][i]|=((B[j]-B[j-1])<<j);
    		tr[x][i]=id[tr[x][i]];
    	}
    }
    void dfs(int x,int state,int res) {
    	if(res<0) return;
    	if(x==10) {
    		id[state]=++m;trans(state);cnt[m]=res;
    		return;
    	}
    	dfs(x+1,state,res);
    	dfs(x+1,state|(1<<x),res+1);
    }
    LL DFS(int len,int lim,int s) {
    	if(!len||cnt[s]>k) return cnt[s]==k;
    	if(!lim&&dp[len][s][k]!=-1) return dp[len][s][k];
    	LL ans=0;
    	for(re int i=0;i<=(lim?lm[len]:9);++i)
    		ans+=DFS(len-1,lim&&(i==lm[len]),tr[s][i]);
    	if(!lim) dp[len][s][k]=ans;
    	return ans;
    }
    inline LL calc(LL N) {
    	if(!N)return 0;int tot=0;
    	while(N) lm[++tot]=N%10ll,N/=10ll;
    	return DFS(tot,1,id[0]);
    }
    int main() {
    	m=0;dfs(0,0,0);memset(dp,-1,sizeof(dp));
    	for(re int i=1;i<=m;i++) Pre_tr(i);tr[id[0]][0]=id[0];
    	int T;scanf("%d",&T);
    	for(re int tnum=1;tnum<=T;++tnum) {
    		scanf("%lld%lld%d",&L,&R,&k);
    		printf("Case #%d: %lld
    ",tnum,calc(R)-calc(L-1));
    	}
    	return 0;
    }
    //g++ hdu4352.cpp -o hdu4352
    
  • 相关阅读:
    ORACLE存储过程调用Web Service
    企业管理应具备哪些软件
    ZROI Day6比赛总结
    UOJ 449 【集训队作业2018】喂鸽子 【生成函数,min-max容斥】
    Atcoder Rating System
    Luogu4688 [Ynoi2016]掉进兔子洞 【莫队,bitset】
    UOJ450 【集训队作业2018】复读机【生成函数】
    Luogu5071 [Ynoi2015]此时此刻的光辉 【莫队】
    Luogu4689 [Ynoi2016]这是我自己的发明 【莫队】
    CF891C Envy【最小生成树】
  • 原文地址:https://www.cnblogs.com/asuldb/p/12141735.html
Copyright © 2011-2022 走看看