3979: 荔枝丹(litchi)

题目描述
绛雪艳浮红锦烂,玉壶光莹水晶寒。

高名已许传新曲,芳味曾经荐大官。

乌府日长霜署静,几株斜覆石栏杆。

——明·陈辉《荔枝》

荔枝(丹),拼音为lizhidan,一种好吃的水果,深得悦色老师的喜爱。

祝阿姨得到了许多许多的荔枝丹,每个荔枝丹上都有一个0到9之间的数字。祝阿姨把它们分成许多组,每组表示一个数,且所有组表示的数字合起来恰好是[L,R]内的所有数。

祝阿姨知道悦色老师特别喜欢吃荔枝丹,于是邀请了悦色老师来吃荔枝丹。悦色老师最喜欢吃有数字0
的荔枝丹了,她吃掉了所有数字为0的荔枝丹。

祝阿姨想知道还剩下多少不同的组。注意悦色老师吃完后,荔枝丹就无序了,也就是说123和321是同样的组。

输入
一行两个正整数
【L,R】。

输出
一行一个整数,表示还剩下多少不同的组。

样例输入
【样例1输入】
1 10

【样例2输入】
40 57

【样例3输入】
157 165

样例输出
【样例1输出】
9
【样例2输出】
17
【样例3输出】
9

solution
如果补上前缀0,使得所有数字位数相等,并把数字看成字符串,并把字符排序,那么问题等价于有多少不同的字符串。

不同的字符串个数不超过C(27,9)=4686824个
所以只需要判断每一个不同的字符串是否再L-R之间
然后通过构造加上一个pd(分类讨论)函数即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<map>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
int n,L[21],R[21],s[15],ans;
long long l,t,r;
bool pd(int k,bool fl,bool fr)
{
    if(k>18)return true;
    if(fl&&fr)
    {
        if(L[k]!=R[k])
        {
            for(int i=L[k]+1;i<R[k];++i)if(s[i])return true;
            bool res1=0,res2=0;
            if(s[L[k]])s[L[k]]--,res1=pd(k+1,1,0),s[L[k]]++;
            if(s[R[k]])s[R[k]]--,res2=pd(k+1,0,1),s[R[k]]++;
            if(res1||res2)return true;
            return false;
        }
        else
        {
            if(!s[L[k]])return false;
            bool res=0;
            s[L[k]]--;res=pd(k+1,1,1);s[L[k]]++;
            return res;
        }
    }
    if(fl&&!fr)
    {
        for(int i=L[k]+1;i<10;++i)if(s[i])return true;
        if(!s[L[k]])return false;
        s[L[k]]--;bool res=0;
        res=pd(k+1,1,0);s[L[k]]++;
        return res;
    }
    if(!fl&&fr)
    {
        for(int i=0;i<R[k];++i)if(s[i])return true;
        if(!s[R[k]])return false;
        s[R[k]]--;bool res=0;
        res=pd(k+1,0,1);s[R[k]]++;
        return res;
    }
}
void work(int x,int Max)
{
    if(x>18){if(pd(1,1,1))ans++;return;}
    for(int i=Max;i<=9;++i){s[i]++;work(x+1,i);s[i]--;}
}
int main()
{
    cin>>l>>t;
    r=t;
    if(t==1e18)r--;
    long long x=l;
    for(int i=18;i;--i,x/=10)L[i]=x%10;
    x=r;
    for(int i=18;i;--i,x/=10)R[i]=x%10;
    work(1,0);
    cout<<ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值