链接:http://www.51nod.com/onlineJudge/submitDetail.html#!judgeId=108709
分析:在枚举每一位观察到 212需要3次,121只要2次,我们可以发现若新枚举的数在前面的一个递增状态没出现过,操作数+1。
比如:前面的状态为“1 2 3 4 5 6” 再加入5时 状态变为“1 2 3 4 5”, 因为后面如果再加入6就会形成“12345656” 操作数还是要+1.
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 21
#define Mm 1026
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CLRS(a,b,Size) memset((a),(b),sizeof((a[0]))*(Size+1))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int a[Mn];
int vis[Mn][Mm][Mn],K;
ll dp[Mn][Mm][Mn];
int s[12],p[12];
ll cal(int len,int pre,int isM,int k) {
if(len==0) return k==K;
if(!isM) {
if(vis[len][pre][k]) return dp[len][pre][k];
vis[len][pre][k]=1;
for(int i=0;i<=9;i++)
if(pre&s[i]) dp[len][pre][k]+=cal(len-1,pre&p[i],0,k);
else dp[len][pre][k]+=cal(len-1,(pre&p[i])|s[i],0,k+(i!=0));
return dp[len][pre][k];
} else {
ll re=0;
for(int i=0;i<=a[len];i++)
if(pre&s[i]) re+=cal(len-1,pre&p[i],i==a[len],k);
else re+=cal(len-1,(pre&p[i])|s[i],i==a[len],k+(i!=0));
return re;
}
}
ll solve(ll x) {
int cnt=0;
while(x) {
a[++cnt]=x%10;
x/=10;
}
return cal(cnt,0,1,0);
}
int main() {
CLR(vis,0);
CLR(dp,0);
s[0]=p[0]=0;
for(int i=1;i<=9;i++) {
s[i]=1<<(i-1);p[i]=(1<<i)-1;
}
ll l,r;
scanf("%lld%lld%d",&l,&r,&K);
printf("%lld\n",solve(r)-solve(l-1));
return 0;
}