Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 9276 | Accepted: 5743 |
Description
Input
Output
Sample Input
13 15 2003 2005 239 250 1399 1500 999999 0
Sample Output
13: 12 15: 13 2003: 1461 2005: 1462 239: 197 250: 198 1399: 1052 1500: 1053 999999: 531440
Source
题目大意:有个计程器,它遇到4会跳过去(只要数字里含4就会跳过去),如123,+1的话本应该是124,但它跳过去之后是125;如399跳过去后是500。给你一个跳过去之后的数,让你求这个数实际上是多少?
解题思路:输入n,相当于求1~n中不带4的数的个数。如求13599,我们这样看:
①13599->10000,先求10000以内的不含四的数的个数:那么这些数相当于0xxxx这样,0xxxx这样的数中,根据排列组合,只含一个4的数有c(4,1)*9*9*9种(一个位置选4,其余3个位置的选0~9中不是四的数就行),只含两个4的数的个数为c(4,2)*9*9,只含3个4的数的个数为c(4,3)*9,含4个4的数的个数为c(4,4)这样,10000以内含四的数有1*(c(4,1)*9*9*9+c(4,2)*9*9+c(4,3)*9+c(4,4));
②求10000到13000中含四的数的个数,相当于求0~3000中含四的数的个数,然后就是类似于①了,化为求3000内含四的数的个数:3*(c(3,1)*9*9+c(3,2)*9+c(3,3)),前面乘的三是说3000内第一位可以是0,1,2.
③求13000到13500中含4的数的个数:相当于求0~500中含四的数的个数,结果是5*(c(2,1)*9+c(2,2))+100-(c(2,1)*9+c(2,2)),+100是说最高位为4,那么就有100中情况,-(c(2,1)*9+c(2,2))是说之前5倍的(c(2,1)*9+c(2,2))多算了4开头的数的个数,那么结果就是(5-1)*(c(2,1)*9+c(2,2))+100.
④求13500~13590...
⑤求13590~13599
算出后用n-含四的数的个数就得出结果了。
注意题目中说输入保证不含4.
综合下:对于每一位数x,设这个数所在位数为i(1<=i<=最高位),若x>4则贡献为(x-1)*(∑c(i-1,k)*pow(9,i-1-k)(k∈(1,i-1)))+pow(10,i-1);
若x<4则贡献为(x)*(∑c(i-1,k)*pow(9,i-1-k)(k∈(1,i-1)));
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int jiu[10];
int jiecheng[10];
int a[10];
int c[10][10];
void dabiao()
{
for(int i=0;i<10;i++)//把9的多少次方打表,乘9乘9乘9就不用一个一个算了
{
jiu[i]=pow(9,i);
}
jiecheng[0]=1;
jiecheng[1]=1;
for(int i=2;i<10;i++)//阶乘打表,为下面的c(n,m)所用
{
jiecheng[i]=jiecheng[i-1]*i;
}
for(int i=1;i<10;i++)//题目说最多是999999999,共9位数,那么我们公式中最多用到c(8,8)
{
for(int j=1;j<=i;j++)
{
c[i][j]=jiecheng[i]/(jiecheng[i-j]*jiecheng[j]);//排列组合公式
}
}
}
int he(int di)
{
int q=0;
for(int i=1;i<=di;i++)
{
q=q+c[di][i]*jiu[di-i];
}
return q;
}
int calc(int x)
{
int shu=a[x];
if(shu<4)
{
return shu*he(x-1);//公式
}
else
{
return (shu-1)*he(x-1)+pow(10,x-1);//公式
}
}
int main()
{
int n;
dabiao();
while(scanf("%d",&n)!=EOF)
{
if(n==0)
{
break;
}
int cnt=1;
int tmp=n;
while(tmp)//分解这个数到数组
{
a[cnt++]=tmp%10;
tmp=tmp/10;
}
int ans=0;
for(int i=cnt-1;i>=1;i--)//对每一位数的贡献进行计算
{
ans=ans+calc(i);
}
printf("%d: %d\n",n,n-ans);//算出的是含四的数的个数,记得用n减去它
}
return 0;
}