2020 Multi-University Training Contest 3 1006 X Number

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6796

题意:有11中类别,分别为0到10类别,如果某一个数他数中出现最多次数的是d(0<=d<=9),那这个数是d类别,比如233中3出现了2次,是最多的,所以是3类别,如果最多出现的不止一个数字,那就是10类别,比如22334,现在给你一个区间[l,r]和类别d(0<=d<=9),问你这个区间中有多少个数是d类别的。

思路:首先肯定会想到数位dp,但会发现进行记忆化搜索时那个状态不好确定。这里就可以进行魔改,当你搜索到上一个数字已经不处于边界时,知道了d数字的个数已经其他数字的个数,就可以用组合数算出来。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[20],b[20],c[20][20];
ll x,l,r;
map<array<int,10>,ll>dp[20][2];
array<int,10>state= {0};
ll fun(int n,int m)
{
    m=max(m,n-m);
    if(c[n][m]!=-1)
        return c[n][m];
    ll ans=1;
    for(int i=m+1; i<=n; i++)
        ans*=i;
    for(int i=1; i<=n-m; i++)
        ans/=i;
    return c[n][m]=ans;
}
ll dfs(int len,bool maxi,bool f)
{
    if(dp[len][f].find(state)!=dp[len][f].end()&&maxi==0)
        return dp[len][f][state];
    if(!len)
    {
        for(int i=0; i<10; i++)
            if(i!=x&&state[i]>=state[x])
                return dp[len][f][state]=0;
        return dp[len][f][state]=1;
    }
    ll res=0,maxn=maxi?a[len]:9;
    if(f&&!maxi)
    {
        for(int i=0; i<=len; i++)
        {
            for(int i0=0; i0<=len-i; i0++)
                b[i0]=0;
            b[len-i]=fun(len,i);
            for(int i0=0; i0<10; i0++)
            {
                if(i0==x)
                    continue;
                if(state[x]+i<=state[i0])
                {
                    b[0]=0;
                    break;
                }
                for(int i1=0; i1<=len-i; i1++)
                {
                    for(int i2=1; i2<=min(i1,state[x]+i-state[i0]-1); i2++)
                    {
                        b[i1-i2]+=fun(i1,i2)*b[i1];
                    }
                }
            }
            res+=b[0];
        }
        return dp[len][f][state]=res;
    }
    for(int i=0; i<=maxn; i++)
    {
        if(i||f)
        {
            if(i==x||state[i]+2<state[x]+len)
            {
                state[i]++;
                res+=dfs(len-1,maxi&&i==a[len],1);
                state[i]--;
            }
        }
        else
            res+=dfs(len-1,maxi&&i==a[len],0);
    }
    return maxi?res:dp[len][f][state]=res;
}
ll div(ll tmp)
{
    int p=0;
    while(tmp)
        a[++p]=tmp%10,tmp/=10;
    ll res=0;
    res+=dfs(p,1,0);
    return res;
}
int main()
{
    memset(c,-1,sizeof(c));
    int T;
    cin>>T;
    while(T--)
    {
        for(int i=0; i<20; i++)
            for(int i1=0; i1<2; i1++)
                dp[i][i1].clear();
        cin>>l>>r>>x;
        cout<<div(r)-div(l-1)<<endl;
    }
}

  

猜你喜欢

转载自www.cnblogs.com/zcb123456789/p/13399698.html