九度OJ 1491 清华大学2012机试 《求1和2的个数》

给定正整数N,函数F(N)表示小于等于N的自然数中1和2的个数之和,例如:1,2,3,4,5,6,7,8,9,10序列中1和2的个数之和为3,因此F(10)=3。输入N,求F(N)的值,1= 输入:
输入包含多组测试数据,每组仅输入一个整数N。
输出:
对于每组测试数据,输出小于等于N的自然数中1和2的个数之和,且对20123取模。
样例输入:
10
11
样例输出:

3

5


看了一份别人的代码,十分简略,不明白怎么做的,就发到了论坛里,有人给讲解了,讲得很棒

比如输入12345,那么先算F(1),再由F(1)算出F(12),依次再算出F(123),F(1234),F(12345);
主要计算的就是rslt=(rslt-cnt)*10+num*2+cnt*(t+1)+min(t,2);这一句了。
rslt是结果;num是实际输入的数;cnt是num这个数中1,2的数量;


首先认为已经算出了F(12)=rslt,需要算F(123)


1.显然12变成了12X的形式,所以原来1-11中每一个数都可以加上一个个位(因为不知道个位是不是9,所以最后一个12不能乘10,以后单独计算),而个位是从0-9,所以原来的每个数都有10中变化,而最后一个数12的1,2的数量为cnt,所以有(rslt-cnt)*10,;

(比如比12小的有1,2的数是:1,2,10,11,扩大十倍后,有10-19,20-29,100-109,110-119,每个数各对应十个数,他们原本的的1和2被加了十次,所以乘以10)

2.上一步中余有一个12没有计算,显然12X这个数的个位只能是0-3,所以有cnt*(t+1);

(t是X位的数,cnt是12的1,2个数,为2,t从0开始,所以是cnt*(t+1)个)
3.上面的计算中都没有考虑对个位为1,2的计数,00-11中个位为1,2的显然是每10个数中有2个,所以有num*2
4.12X个位的1,2个数,直接判断就好了,min(t,2);


#include #include #include using namespace std; int main() { char N[110] = {0}; while(cin>>N) { int i,t = 0; int result,num,cnt; //result是结果,num是当前计算的N,cnt即num这个数中的1,2个数 result = num = cnt = 0; int len = strlen(N); for(i = 0; i < len; i++) { t = N[i] - '0'; result = (result - cnt)*10 + cnt*(t+1) + num*2 + min(t,2); num = num*10 + t; if(t == 1 || t == 2) cnt++; num %= 20123; result %= 20123; } printf("%d\n",result); } return 0; }



你可能感兴趣的:(偶尔ACM打酱油)