前几天编程班考试时发现第二题很有意思,大概是 NOIP 普及组第二题的难度,感兴趣的可以看看
problem2:有故障的打字机(typewrt)
●题目描述
一台打字机准备将 1到10^n 的数依次打出。在打印过程中,这台打字机出现了一个故障:数字“3”打不出来。因此,所有含有数字“3”的数都没有被正确地打出。试问没有被正确打出的数一共有多少个。
●输入格式
输入一个正整数n。
●输出格式
输出从1到 10^n 这些数中不能被正确打印的数的个数。
●输入输出样例
#1 输入:
2
#1 输出:
19
●规模限制
各测试点1秒,你的程序将被分配32MB的运行空间,保证 n<=1000 。
思考时间......
●我的思路
首先,看到数据范围就知道暴力肯定过不了,那么有什么其他办法呢?
我们首先把 n 为不同值时的答案算出来,记录如下:
n=1时:答案为
=1
n=2时:答案为
=19
n=3时:答案为
=271
数学好一点的小盆友们很快就能发现规律:
到这一步,思路就基本出来了,只需要用高精度乘单精度算出和
,再用高精度减法算出它们相减即可
●AC代码
#include<bits/stdc++.h>
using namespace std;
int a[1024],b[1024];//a[]==9^n,b[]=10^n
int n,lenb,lena;
void chen()
{
for(int i=1;i<=lena;i++)
a[i]*=9;
int jw=0;
for(int i=1;i<=lena;i++)
{
a[i]+=jw;
jw=(a[i]/10);
a[i]%=10;
}
while(jw)
{
++lena;
a[lena]=jw%10;
jw/=10;
}
}
void dec()//10^n-9^n;
{
int len=max(lena,lenb);
for(int i=1;i<=len;i++)//先减
b[i]-=a[i];
for(int i=1;i<=len;i++)//后处理进位
{
if(b[i]<0)
{
b[i]+=10;
--b[i+1];
}
}
while(!b[lenb])
--lenb;
}
int main(void)
{
//freopen("typewrt.in","r",stdin);
//freopen("typewrt.out","w",stdout);
cin>>n;
b[n+1]=1;//10^n
lenb=n+1;
a[1]=1;
lena=1;
while(n--) chen();
dec();
for(int i=lenb;i>=1;i--)
cout<<b[i];
cout<<endl;
return 0;
}
完结撒花!!!dalao们有其他思路可以在评论区交流,Thanks♪(・ω・)ノ!
●题外话
有没有dalao有推荐的讲述贪心算法的文章,蒟蒻想要深入了解一下这个算法,有的话私信我,谢谢。