zoukankan      html  css  js  c++  java
  • [HDU4352]XHXJ's LIS

    题面在这里

    description

    定义(f(i))表示将(i)看成字符串的最长上升子序列长度。
    给定(l),(r),(k),求满足(lle ile r)(f(i)=k)的个数。

    data range

    [1le lle rle 10^{18},1le kle 10 ]

    solution

    一开始的思路是使用数位(DP),(f[i][j][k][0/1])
    表示第(i)位尾数为(j),(log n)做法的单调序列情况为(k);

    一开始想象单调队列的情况需要存(10^{10})种,复杂度会超时。
    但考虑优化状态,可以发现这个单调序列有一些特殊的性质:
    1 长度至多为10
    2 可能出现的数字只有0-9,并且不重复
    3 这个序列是单调递增的

    有了这些性质,我们可以知道
    对于每一个单调序列中数字0-9的存在情况,满足要求的队列有且只有一个
    因此,我们使用二进制表示0-9是否存在于单调队列的状态,
    这样([k])这一位的空间就变成了(2^{10}=1024)
    状态可以继续优化成(f[i][k][0/1]),
    于是总理论复杂度变为(O(Tlen(n)2^{10} imes 10)),
    比之前有所降低,但仍旧无法通过

    解决前导0问题的方法:记忆化搜索!!!

    //数位DP的记忆化搜索
    int a[MAX_LEN],f[MAX_LEN][MAX_F]
    //一般来说记忆化数组f记录的是q和zr全都为0的情况
    ll dfs(int p,int s,bool q,bool z){
        //数位,附加状态,危险态/安全态,是否有前导0
        if(p==-1)return check(s);
        //检查附加状态s是否符合要求,如果符合贡献+1
        if(!q&&!z&&f[p][s]!=-1)return f[p][s];
        int ans=0;
        for(RG int i=0,end=(q?a[p]:9);i<=end;i++)
            if(z&&!i)ans+=dfs(i-1,s,q&&i==end,1);
            else ans+=dfs(i-1,to[s][i],q&&i==end,0);
        //to[s][i]指附加状态s通过i转移后的新状态
        if(!q&&!z)f[p][s]=ans;return ans;
    }
    void solve(ll x){
        RG int len=0;while(x){a[len++]=x%10;x/=10;}
        //按照低位在前的顺序放好
        return dfs(len,0,1,1);
    }
    

    多组询问我们可以考虑记忆化搜索来降低实际时间复杂度,
    然后通过预处理转移来降低常数

    code

    #include<bits/stdc++.h>
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<iomanip>
    #include<cstring>
    #include<complex>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    //#define TEST
    #define FILE "a"
    #define mp make_pair
    #define pb push_back
    #define RG register
    #define il inline
    using namespace std;
    typedef unsigned long long ull;
    typedef vector<int>VI;
    typedef long long ll;
    typedef double dd;
    const int inf=1e9+7;
    const int mod2=998244353;
    const int rev2=332748118;
    const int mod1=1e9+7;
    const int N=3010;
    const dd eps=1e-10;
    const ll INF=1e18;
    const int g=3;
    il ll read(){
      RG ll data=0,w=1;RG char ch=getchar();
      while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
      if(ch=='-')w=-1,ch=getchar();
      while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
      return data*w;
    }
    
    il void file(){
      freopen(FILE".in","r",stdin);
      freopen(FILE".out","w",stdout);
    }
    
    int k,cnt[1024],que[1024][10],to[1024][10],a[20];
    il void getque(int x){
    	for(RG int i=0;i<=9;i++)
    		if(x&(1<<i))que[x][++cnt[x]]=i;
    }
    il int getnxt(int x,int y){
    	for(RG int i=y;i<=9;i++)
    		if(x&(1<<i))return x^(1<<i)|(1<<y);
    	return x|(1<<y);
    }
    
    il void print(int x){
    	for(RG int i=0;i<=9;i++)
    		if(x&(1<<i))printf("%d ",i);
    }
    
    ll f[20][1024][11];
    il bool check(int s){return cnt[s]==k;}
    il ll dfs(int p,int s,bool q,bool z){
    	if(p==-1){return check(s);}
    	if(!q&&!z&&f[p][s][k]!=-1){return f[p][s][k];}
    	ll ans=0;int end=(q?a[p]:9);
    	for(RG int i=0;i<=end;i++){
    		if(z&&!i)ans+=dfs(p-1,0,q&&i==end,1);
    		else ans+=dfs(p-1,to[s][i],q&&i==end,0);
    	}
    	if(!q&&!z)f[p][s][k]=ans;return ans;
    }
    
    il ll DP(ll n){
    	RG int len=0;while(n){a[len++]=n%10;n/=10;}
    	return dfs(len-1,0,1,1);
    }
    
    int main()
    {
    	memset(f,-1,sizeof(f));
    	for(RG int i=0;i<1024;i++){
    		getque(i);
    		for(RG int j=0;j<=9;j++)
    			to[i][j]=getnxt(i,j);
    	}
    
    	RG int T=read();
    	for(RG int i=1;i<=T;i++){
    		ll l=read();ll r=read();k=read();
    		printf("Case #%d: %lld
    ",i,DP(r)-DP(l-1));
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    php获取真实ip地址原理及实现
    关于DateTime计算某个日期过后的多少天之后的日期
    关于get_include_path()和set_include_path()的问题
    LinQ In Action 学习第三章
    LinQ In Action 学习第二章
    LinQ in Action 学习第一章 例子。
    asp.net create windows application and setup service.
    JS alert()、confirm()、prompt()的区别
    php获取用户 地区 、ip地址
    购物车相关 js
  • 原文地址:https://www.cnblogs.com/cjfdf/p/9043369.html
Copyright © 2011-2022 走看看