求1和2的个数

strom 2013-07-31 04:44:25
题目描述:
给定正整数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<=10^100(10的100次方)若F(N)很大,则求F(N)mod20123的值。
输入:
输入包含多组测试数据,每组仅输入一个整数N。
输出:
对于每组测试数据,输出小于等于N的自然数中1和2的个数之和,且对20123取模。
样例输入:10
11样例输出:
3
5

如何统计1的个数??
...全文
684 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
54se3 2014-03-05
  • 打赏
  • 举报
回复
可行代码:

#include <iostream>
#include <algorithm>

using namespace std;

string s;
int a[128];//10^n模20123
int b[128];//n个全9中1,2出现总次数
int c[128];//低n位模20123

int main()
{
    int i;
	int r, t;

	a[0] = 1;
	b[0] = 0;
	for ( i = 1; i < 128; i++ ) {
		b[i] = ( 2 * i * a[i - 1] ) % 20123;
		a[i] = ( a[i - 1] * 10 ) % 20123;
	}

	while ( cin >> s ) {
		s += '#';
		reverse( s.begin(), s.end() );
		c[0] = 1;
		for ( i = 1; i < s.length(); i++ ) {
			s[i] -= '0';
			c[i] = ( s[i] * a[i - 1] + c[i - 1] ) % 20123;
		}

		r = 0;
		for ( i = s.length() - 1; i >= 1; i-- ) {
			r = ( r + s[i] * b[i - 1] ) % 20123;
			if ( s[i] == 1 ) {
				r = ( r + c[i - 1] ) % 20123;
			}
			else if ( s[i] == 2 ) {
				r = ( r + c[i - 1] + a[i - 1] ) % 20123;
			}
			else if ( s[i] > 2 ) {
				r = ( r + 2 * a[i -  1] ) % 20123;
			}
		}

		cout << r << endl;
	}
	 
	return 0;
}
FancyMouse 2013-08-02
  • 打赏
  • 举报
回复
引用 15 楼 wangyulinyy 的回复:
引用 13 楼 nice_cxf 的回复:
题目还是很麻烦的,还要考虑开头是1或者2的情况,本来以为一个简单的递归就ok的
递归肯定超时!
他的意思是像我的代码那样的递归(虽然我写成了循环)。递归层数等于输入数字的长度。
strom 2013-08-01
  • 打赏
  • 举报
回复
引用 13 楼 nice_cxf 的回复:
题目还是很麻烦的,还要考虑开头是1或者2的情况,本来以为一个简单的递归就ok的
递归肯定超时!
strom 2013-08-01
  • 打赏
  • 举报
回复
引用 8 楼 zhao4zhong1 的回复:
[quote=引用 6 楼 namelij 的回复:] [quote=引用 2 楼 zhao4zhong1 的回复:] 仅供参考
#include <stdio.h>
#include <string.h>
#define MAXLEN 1000
char a1[MAXLEN];
char a2[MAXLEN];
static int v1[MAXLEN];
static int v2[MAXLEN];
static int v3[MAXLEN];
int i,j,n,L,z;
void main(void) {
    scanf("%d",&n);
    for (j=0;j<n;j++) {
        scanf("%s%s",a1,a2);

        L=strlen(a1);
        for (i=0;i<L;i++) v1[i]=a1[L-1-i]-'0';

        L=strlen(a2);
        for (i=0;i<L;i++) v2[i]=a2[L-1-i]-'0';

        for (i=0;i<MAXLEN;i++) v3[i]=v1[i]+v2[i];

        for (i=0;i<MAXLEN;i++) {
            if (v3[i]>=10) {
                v3[i+1]+=v3[i]/10;
                v3[i]=v3[i]%10;
            }
        }

        printf("Case %d:\n", j+1);
        printf("%s + %s = ", a1, a2);

        z=0;
        for (i=MAXLEN-1;i>=0;i--) {
            if (z==0) {
                if (v3[i]!=0) {
                    printf("%d",v3[i]);
                    z=1;
                }
            } else {
                printf("%d",v3[i]);
            }
        }
        if (z==0) printf("0");

        printf("\n");
    }
}
//Sample Input
//3
//0 0
//1 2
//112233445566778899 998877665544332211
//
//Sample Output
//Case 1:
//0 + 0 = 0
//Case 2:
//1 + 2 = 3
//Case 3:
//112233445566778899 + 998877665544332211 = 1111111111111111110
几年不见,赵大妈的代码风格还是一如既往的烂[/quote] 比用什么风格更重要的是在任何地方,任何时候都坚持用一种风格。 比爱哪种美眉更重要的是在任何地方,任何时候都坚持爱一个美眉。 [/quote]你这是大数加法吧???我题目不是这个意思
nice_cxf 2013-08-01
  • 打赏
  • 举报
回复
题目还是很麻烦的,还要考虑开头是1或者2的情况,本来以为一个简单的递归就ok的
FancyMouse 2013-08-01
  • 打赏
  • 举报
回复

#include <iostream>
#include <string>
using namespace std;

const int MOD = 20123;
int pow(int n, int exp)
{
	if(exp == 0)
		return 1;
	int t = pow(n * n % MOD, exp / 2);
	if(exp % 2 == 1)
		t = t * n % MOD;
	return t;
}
int pnm(int b, int e, int n)
{
	return n * pow(b, e) % MOD;
}
void Add(int& r, int v)
{
	r = (r + v) % MOD;
}
int judge(int digit)
{
	switch(digit)
	{
	case 1:
	case 2:
		return 1;
	default:
		return 0;
	}
}
int main()
{
	string num;
	int x[10];
	x[0] = judge(0);
	for(int i=1;i<10;i++)
		x[i] = x[i-1] + judge(i);
	while(cin>>num)
	{
		int cnt = 0;
		int result = 0;
		int len = num.size();
		for(int i=0;i<len;i++)
		{
			int digit = num[i] - '0';
			if(i < len-1)
				Add(result, pnm(10, len-2-i, x[9]*digit*(len-1-i)));
			if(digit > 0)
				Add(result, pnm(10, len-1-i, x[digit-1]));
			Add(result, pnm(10, len-1-i, cnt*digit));
			cnt += judge(digit);
		}
		Add(result, cnt);
		cout<<result<<endl;
	}
	return 0;
}
一帮人在瞎搞。
赵4老师 2013-08-01
  • 打赏
  • 举报
回复
引用 10 楼 hello_world000 的回复:
找规律,找公式,参考《编程之美》
小学奥数总讲类似题目。 9楼代码可以用来在1~100000000范围内验证公式。
hello_world000 2013-08-01
  • 打赏
  • 举报
回复
找规律,找公式,参考《编程之美》
赵4老师 2013-08-01
  • 打赏
  • 举报
回复
抛砖引玉:(警告:>100000000就很慢了!)
//题目描述:
// 给定正整数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<=10^100(10的100次方)若F(N)很大,则求F(N) mod 20123的值。
//输入:
// 输入包含多组测试数据,每组仅输入一个整数N。
//输出:
// 对于每组测试数据,输出小于等于N的自然数中1和2的个数之和,且对20123取模。
//样例输入:
// 10
// 11
//样例输出:
// 3
// 5
#include <stdio.h>
#include <string.h>
#define MAXLEN 102
char a0[MAXLEN];
int v0[MAXLEN];
int v1[MAXLEN];
int i,j,L,n;
void main(void) {
    while (1) {
        if (1!=scanf("%101s",a0)) break;
        memset(v0,0,MAXLEN*sizeof(int));
        L=strlen(a0);
        for (i=0;i<L;i++) v0[i]=a0[L-1-i]-'0';
        n=0;
        memset(v1,0,MAXLEN*sizeof(int));
        while (1) {
            for (i=0;i<L;i++) if (v1[i]!=v0[i]) break;
            for (j=0;j<L;j++) if (v1[j]==1 || v1[j]==2) {n++;n=n%20123;}
            if (i>=L) break;
            v1[0]++;
            for (i=0;i<L;i++) {
                if (v1[i]>=10) {
                    v1[i+1]+=v1[i]/10;
                    v1[i]=v1[i]%10;
                }
            }
        }
        printf("%d\n",n);
    }
}
赵4老师 2013-08-01
  • 打赏
  • 举报
回复
引用 6 楼 namelij 的回复:
[quote=引用 2 楼 zhao4zhong1 的回复:] 仅供参考
#include <stdio.h>
#include <string.h>
#define MAXLEN 1000
char a1[MAXLEN];
char a2[MAXLEN];
static int v1[MAXLEN];
static int v2[MAXLEN];
static int v3[MAXLEN];
int i,j,n,L,z;
void main(void) {
    scanf("%d",&n);
    for (j=0;j<n;j++) {
        scanf("%s%s",a1,a2);

        L=strlen(a1);
        for (i=0;i<L;i++) v1[i]=a1[L-1-i]-'0';

        L=strlen(a2);
        for (i=0;i<L;i++) v2[i]=a2[L-1-i]-'0';

        for (i=0;i<MAXLEN;i++) v3[i]=v1[i]+v2[i];

        for (i=0;i<MAXLEN;i++) {
            if (v3[i]>=10) {
                v3[i+1]+=v3[i]/10;
                v3[i]=v3[i]%10;
            }
        }

        printf("Case %d:\n", j+1);
        printf("%s + %s = ", a1, a2);

        z=0;
        for (i=MAXLEN-1;i>=0;i--) {
            if (z==0) {
                if (v3[i]!=0) {
                    printf("%d",v3[i]);
                    z=1;
                }
            } else {
                printf("%d",v3[i]);
            }
        }
        if (z==0) printf("0");

        printf("\n");
    }
}
//Sample Input
//3
//0 0
//1 2
//112233445566778899 998877665544332211
//
//Sample Output
//Case 1:
//0 + 0 = 0
//Case 2:
//1 + 2 = 3
//Case 3:
//112233445566778899 + 998877665544332211 = 1111111111111111110
几年不见,赵大妈的代码风格还是一如既往的烂[/quote] 比用什么风格更重要的是在任何地方,任何时候都坚持用一种风格。 比爱哪种美眉更重要的是在任何地方,任何时候都坚持爱一个美眉。
lm_whales 2013-08-01
  • 打赏
  • 举报
回复
累加和计算时,直接 求F(N)mod20123;
  • 打赏
  • 举报
回复
引用 2 楼 zhao4zhong1 的回复:
仅供参考
#include <stdio.h>
#include <string.h>
#define MAXLEN 1000
char a1[MAXLEN];
char a2[MAXLEN];
static int v1[MAXLEN];
static int v2[MAXLEN];
static int v3[MAXLEN];
int i,j,n,L,z;
void main(void) {
    scanf("%d",&n);
    for (j=0;j<n;j++) {
        scanf("%s%s",a1,a2);

        L=strlen(a1);
        for (i=0;i<L;i++) v1[i]=a1[L-1-i]-'0';

        L=strlen(a2);
        for (i=0;i<L;i++) v2[i]=a2[L-1-i]-'0';

        for (i=0;i<MAXLEN;i++) v3[i]=v1[i]+v2[i];

        for (i=0;i<MAXLEN;i++) {
            if (v3[i]>=10) {
                v3[i+1]+=v3[i]/10;
                v3[i]=v3[i]%10;
            }
        }

        printf("Case %d:\n", j+1);
        printf("%s + %s = ", a1, a2);

        z=0;
        for (i=MAXLEN-1;i>=0;i--) {
            if (z==0) {
                if (v3[i]!=0) {
                    printf("%d",v3[i]);
                    z=1;
                }
            } else {
                printf("%d",v3[i]);
            }
        }
        if (z==0) printf("0");

        printf("\n");
    }
}
//Sample Input
//3
//0 0
//1 2
//112233445566778899 998877665544332211
//
//Sample Output
//Case 1:
//0 + 0 = 0
//Case 2:
//1 + 2 = 3
//Case 3:
//112233445566778899 + 998877665544332211 = 1111111111111111110
几年不见,赵大妈的代码风格还是一如既往的烂
lm_whales 2013-08-01
  • 打赏
  • 举报
回复
找一下规律,不要暴力算法,不然时间够呛。 1)找K 位数里,1,2 的个数 2)找 1~ N (10^100) 里最大数是多少位 M 3)计算 1到M-1位数的1,2个数的累加和 4)计算 最小的M位数里~最大的M位数共有多少1,和2 累加即可。 这应该是最快的一种了。 计算过程有点复杂。
nice_cxf 2013-07-31
  • 打赏
  • 举报
回复
。。。这数量级你们穷举?实际就是排列组合,不过10的100次方也太坑爹了,还要用大数 举个简单的例子输入999,百位上是1或2的有200个,10位上也是200个,个位上也是200个,一共600
syscofield 2013-07-31
  • 打赏
  • 举报
回复

while(a)//以整数a为例
{
if(1==a%10)//取a最后一位与1比较
count++;//记录1的个数
a=a/10;//去掉a最后一位,若此时a不为0则继续循环。
}
希望对你有所帮助。。。
赵4老师 2013-07-31
  • 打赏
  • 举报
回复
仅供参考
#include <stdio.h>
#include <string.h>
#define MAXLEN 1000
char a1[MAXLEN];
char a2[MAXLEN];
static int v1[MAXLEN];
static int v2[MAXLEN];
static int v3[MAXLEN];
int i,j,n,L,z;
void main(void) {
    scanf("%d",&n);
    for (j=0;j<n;j++) {
        scanf("%s%s",a1,a2);

        L=strlen(a1);
        for (i=0;i<L;i++) v1[i]=a1[L-1-i]-'0';

        L=strlen(a2);
        for (i=0;i<L;i++) v2[i]=a2[L-1-i]-'0';

        for (i=0;i<MAXLEN;i++) v3[i]=v1[i]+v2[i];

        for (i=0;i<MAXLEN;i++) {
            if (v3[i]>=10) {
                v3[i+1]+=v3[i]/10;
                v3[i]=v3[i]%10;
            }
        }

        printf("Case %d:\n", j+1);
        printf("%s + %s = ", a1, a2);

        z=0;
        for (i=MAXLEN-1;i>=0;i--) {
            if (z==0) {
                if (v3[i]!=0) {
                    printf("%d",v3[i]);
                    z=1;
                }
            } else {
                printf("%d",v3[i]);
            }
        }
        if (z==0) printf("0");

        printf("\n");
    }
}
//Sample Input
//3
//0 0
//1 2
//112233445566778899 998877665544332211
//
//Sample Output
//Case 1:
//0 + 0 = 0
//Case 2:
//1 + 2 = 3
//Case 3:
//112233445566778899 + 998877665544332211 = 1111111111111111110
  • 打赏
  • 举报
回复
转换为字符串,遍历每个数,逢一或二,计数++

65,189

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧