清华 2012 求1和2的个数

题目:

输入正整数N1=<N<=10^100(10100次方)),输出F(N) mod20123F(N)表示小于等于N的自然数中12的个数之和。例如:1,2,3,4,5,6,7,8,9,10,11序列中12的个数之和为5,因此F(11)=5


思路:

Nstring存储,先求出F(N[0]),再求出F(N[0]N[1]),再求出F(N[0]N[1]N[2])……,最后求出F(N)。而由前一个F求出后一个F’,用公式: F’=(F-cons)*10+ cons*(newChar+1) + preNum*2 + min(newChar,2)  假设由F(N[0]…N[i])F(N[0]…N[i]N[i+1]),例如由F(52)F(526):

  • F:                   F(N[0]…N[i])                                              F(52)
  • F’:                  F(N[0]N[i]N[i+1])                                  F(526)   
  • cons:              N[0]—N[i]12的个数。                           1
  • preNum:       N[0]…N[i]这个数字字符串组成的数字。   52
  • newChar:      新的那个数字符号,即N[i+1]                  6

 

公式分为4部分:

  1. (F-cons)*10 :               F(52)中的数(1,2,10,11,…,29,31,32,41,42,51),变成F(526)后,都会依次和0~9组合(10~19,20~29,100~109,…,510~519),所以乘以10。又因为preNum本身不一定能组成preNum0~9,所以交给第二项来单独算(52只能算520~526)
  2. cons*(newChar+1):   见上。
  3. preNum*2 :                F(526)中,个位数也新增加了12,为每10个数中,就必有两个数的个位为12。而526共有preNum(52)个整10(0~519),所以用preNum*2。至于520~526个位数有几个12,要交给第四项单独计算。
  4. min(newChar,2):       见上。

过程:
1.在使用"?:"时,若运算符若非直接赋值,要括号括起来。因为其优先级很低。如:cons=cons+((newChar==1||newChar==2)?1:0);   
   不可cons=cons+(newChar==1||newChar==2)?1:0; 否则会先算加号。       

#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;

int min(int a,int b){
	return a<b?a:b;
}

int main(){
	string N;
	int len,i;
	int F,preNum,cons,newChar;

	while(cin>>N){
		len=N.length();
		F=cons=preNum=newChar=0;

		for(i=0;i<len;i++){                                //由F(N[0])求到F(N[0]N[1]...N[len-1])
			newChar=N[i]-48;
			F=(F-cons)*10 + cons*(newChar+1) + preNum*2 + min(newChar,2);	//套公式计算
			
			preNum=(preNum*10+newChar)%20123;
			cons=cons+((newChar==1||newChar==2)?1:0);                       //?:运算符若非直接赋值,要括号括起来。因为其优先级很低。
			F=F%20123;		
		}
		printf("%d\n",F);                                  //输出结果
	}
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值