WUST OJ 1270:LIS(数位DP)

版权声明:http://blog.csdn.net/Mitsuha_。 https://blog.csdn.net/Mitsuha_/article/details/86674933

1270: LIS
Time Limit: 1 Sec
Memory Limit: 128 MB
64bit IO Format: %lld

Description
给三个整数L,R,K。求闭区间[L,R]内有多少个数A,使得如果把A当成字符串时,它的最长严格递增子序列长度为K,比如12324的最长严格递增子序列长度为4。

Input
多组测试样例。
每组含三个整数L,R,K.占一行。 0 < L < = R < 2 63 1 , 1 = < K < = 10 . (0<L<=R<2^{63}-1,1=<K<=10).

Output
对于每组测试样例输出一个整数,表示满足要求的数的个数,占一行。

Sample Input
123 321 2

Sample Output
139

思路: d [ i ] [ j ] [ k ] d[i][j][k] 表示低 i i 中,第 i i 位的数字为 j j ,且最长上升子序列构成的状态为k的数的个数。

当更新到第 i + 1 i+1 位时,可以采用最长上升子序列 n l o g n nlog n 解法的思想,用当前选中的这个数替代状态 k k 中第一个大于等于它的数。

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e6+10;
const int MOD=1e9+7;
const int INF=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
ll p[20];
ll d[20][10][1<<10];
ll A[20][10][12];
ll low(int x,int y){for(;x>=0;x--)if((1<<x)&y)return 1<<x;return 0;}
ll big(int x,int y){for(;x<=9;x++)if((1<<x)&y)return 1<<x;return 0;}
ll check(int x,int y,int len)
{
    int t=0,q=y,ans=0;
    ans=max(ans,__builtin_popcount(x));
    ans=max(ans,__builtin_popcount(y));
    for(int i=0;(1<<i)<=x;i++)
    {
        q-=(1<<i)&y;
        t+=(1<<i)&x;
        ans=max(ans,__builtin_popcount(t+q));
    }
    return ans==len;
}
ll cal(ll x,int len)
{
    if(x==0)return 0;
    int n=0;
    while(x)p[n++]=x%10,x/=10;n--;
    ll ans=0;
    for(int i=0;i<n;i++)
    for(int j=1;j<=9;j++)ans+=A[i][j][len];//因为我不是用搜索写的,所以没有这个预处理会T
    int S=0;
    for(int i=n;i>=0;i--)
    {
        if(i==n)for(int j=1;j<p[i];j++)ans+=A[i][j][len];
        else
        {
            for(int j=0;j<p[i];j++)
            for(int k=1;k<(1<<10);k++)ans+=check(S,k,len)*d[i][j][k];
        }
        S+=(1<<p[i])-big(p[i],S);
    }
    return ans+(__builtin_popcount(S)==len);
}
int main()
{
    memset(d,0,sizeof d);
    memset(A,0,sizeof A);
    for(int i=0;i<=19;i++)
    {
        if(i==0)
        {
            for(int j=0;j<=9;j++)d[i][j][1<<j]=1;
            continue;
        }
        for(int j=0;j<=9;j++)
        for(int k=0;k<=9;k++)
        for(int S=1;S<(1<<10);S++)
        {
            if(d[i-1][k][S]==0)continue;
            d[i][j][S+(1<<j)-low(j,S)]+=d[i-1][k][S];
        }
        for(int j=0;j<=9;j++)
        for(int S=1;S<(1<<10);S++)A[i][j][__builtin_popcount(S)]+=d[i][j][S];
    }
    ll L,R,K;
    while(scanf("%lld%lld%lld",&L,&R,&K)!=EOF)printf("%lld\n",cal(R,K)-cal(L-1,K));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mitsuha_/article/details/86674933
OJ
今日推荐