题目描述
绛雪艳浮红锦烂,玉壶光莹水晶寒。
高名已许传新曲,芳味曾经荐大官。
乌府日长霜署静,几株斜覆石栏杆。
——明·陈辉《荔枝》
荔枝(丹),拼音为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;
}