SWUN 1433 - Count

10 篇文章 0 订阅


Count

时间限制(普通/Java) : 1000 MS/ 3000 MS          运行内存限制 : 65536 KByte
总提交 : 5            测试通过 : 1

描述

最近Snow_storm一直被一个问题困扰着:他将1到N按顺序从左到右写在纸上,然后在每个数字前交替添加+、-号,并且计算出最后的结果。

例如:当N=12时,+1 -2 +3 -4 +5 -6 +7 -8 +9 -1+0 -1+1 -1+2 = 5。

可是当N比较大的时候,Snow_storm就有点没办法了。因此,对于给定的N,他希望你能帮他计算出最后的结果。

输入

    多组测试数据。

    对于每组测试数据,只有一个行,包含一个整数N(1 <= N <= 10^15)。

输出

    对于每组测试数据,输出相应的计算结果。

样例输入

12

样例输出

5

题目来源

CJ


 


题目地址: http://218.194.91.48/acmhome/problemdetail.do?&method=showdetail&id=1433

 

数论,统计 。。。

 

除了处理比较麻烦,其它实在没什么好讲,。。

 

 

#include<iostream>
#include<cstdio>

using  namespace std;

__int64 s[17],k[17];

void deal(){
// 预处理出 个位数0~9、十位数10~99、百位数100~999 、。。。。 时,分别的sum是多少,储存在s[]中 ...
// k[]储存的 是 十进制数 1 、 10 、 100 、 1000 、10000 。。。。等 
	int i,j,f;
	__int64 tmp;
	s[1]=5;
	tmp=1;
	for(i=2;i<17;i++){
		if((i&1)==0){
			s[i]=-10*45*tmp;
			f=1;
			for(j=2;j<=i;j++){
				s[i]+=9*45*tmp*f;
				f*=-1;
			}
		}
		else s[i]=+45*tmp;
		tmp*=10;
		k[i-1]=tmp;
	}
	k[i-1]=tmp*10;
	k[0]=1;
//	for(i=1;i<=10;i++) printf("%I64d ",s[i]-1);puts("");
}


int main(){
	__int64 n,res,tmp2,tmp;
	int t,f,ff,j,i,flg;
	deal();
	while(~scanf("%I64d",&n)){
		res=0;
		if(n<10){ // n<10 时特殊处理 
			f=1;
			for(i=1;i<=n;i++){
				res+=f*i;
				f*=-1;
			}
		}
		else{ // 如果n>=10  
			for(i=1;i<16;i++)// 先将结果依次加上 小于n的位数:个位数、十位数、百位数 。。。 时的情况。。 
				if(n>=k[i])
					res+=s[i];
				else break;    
			if((i&1)){ // 当n的位数是奇数时 
				tmp=(n-k[i-1])/10;
				tmp2=n%10;
				res+=5*tmp; // 最终结果只加上 最后一位,因为每相邻两数前面的几位,两两抵消 。。 
				f=1;
				for(i=1;i<=tmp2;i++){
			 		res+=i*f;
					f*=-1;
				}
				if((n&1)==0){ // 当然,如果n为奇数,那么它将少一个抵消,于是这个维抵消的数的每一位需要加上 
					n/=10;
					f=1;
					while(n){
						res+=f*(n%10);
						n/=10;
						f*=-1;
					}
				}
			}
			else{ // 当n的位数是偶数时 
				f=-1;
				flg=0;
			    while(i-- && n){ // 每个数的 第一位-,第二位+,第三位-,第四位+,...
				//	因此我们只需要统计一下n范围内,相同位置的数字分别都被+与-了多少次即可。 
					tmp=n/k[i];
					n%=k[i];
					res+=f*(n+1)*tmp;
					if(tmp>0){
						tmp2=tmp*(tmp-1)/2;
						res+=f*tmp2*k[i];
						ff=f*-1;
						if(flg==0) tmp--;
						for(j=i;j>0;j--){
							res+=ff*tmp*45*k[i-1];
							ff*=-1;
						}
					flg=1;
					}
			   		f*=-1;
				}
			}
		}
		printf("%I64d\n",res);
	}
	return 0;
}
/*
1 1
2 -1
3 2
13 7
14 10
15 14
16 19
17 25
80 32
81 25
82 19
83 14
84 10
85 7
395 108
413 117
431 126
449 135
467 144
485 153
611 216
629 225
647 234
665 243
683 252
899 360
917 369
935 378
953 387
971 396
989 405
1180 382
1181 375
1182 369
1183 364
1184 360
1185 357
1186 355
1187 354
1188 354
1189 355
1190 346
1191 338
1192 331
1193 325
1194 320
1195 316
1196 313
1197 311
1198 310
1199 310
1200 311

*/


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值