snoi多校模擬賽 1.16 t2

原題:bzoj2900

2900: 好玩的數字遊戲

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 99  Solved: 59
[Submit][Status][Discuss]

Description

TK在虐題的同時,也喜歡玩遊戲。
現在,有這樣的一個遊戲,規則是這樣的:
先隨機給出一個數字N,然後你在操場上把1到N的所有數字寫成一排,就像這樣:
123456789101112131415….
接着你在每個數字前面添上加減號,每逢排在奇數位上的數字,就寫上加號;每逢排在偶數位上的數字,就寫上減號。恩…最後你得到一個超級長的式子。並且可以算出這個式子的結果。
TK覺得這個遊戲很有意思,於是他沒日沒夜地玩啊玩啊玩啊…
或許你覺得這個遊戲沒有意思…恩…但是,如果你是TK,對於給定的N,你能夠算出來最後的結果應該是多少麼?

Input

多組數據。每個測試點的數據組數不超過1000組。
每一行僅一個正整數N。保證沒有多餘的什麼奇怪的字符。
每個測試點的數據最後一行一定是數字0。代表這個測試點的結束。

Output

 
對於每組數據,輸出相應的結果。

Sample Input

12
0

Sample Output

5

HINT

【樣例說明】


         對於12這個數字:


寫成一行就是:123456789101112


那麼,形成的表達式就是:+1-2+3-4+5-6+7-8+9-1+0-1+1-1+2=5.


【數據範圍】


         對於10%的數據:保證第一行是數字100,第二行是0.


       對於20%的數據:保證數據組數不超過10,N不超過10^5


       對於50%的數據:保證數據組數不超過20,N不超過10^10


       對於100%的數據:保證數據組數不超過100,N不超過10^15


Source

[Submit][Status][Discuss]

題解:先打表找規律,然後你就會發現對於1-9,10-99,100-999,1000-9999的答案如下:5,-45,450,-450;

所以這題就可以把數字分開算了

先算這個數字最多能用規律支持的位

之後分奇偶計算剩下的後綴

f[i][j]表示數字爲j99999.......(i個9)時的答案所以方程如下

if(!j) _[i][j]=_[i-1][9];
else if(i&1) _[i][j]=_[i][j-1]+_[i-1][9]+_10[i-1]*j;
else _[i][j]=_[i][j-1]+_[i-1][9]-_10[i-1]*j;

之後就能輕易的根據奇偶性算前面可以算的位數了(愉快)

但是你會發現最後的賊tm難算

基本思想就是根據數字排列的奇偶性

奇數除最後一位全部抵消

偶數則會一直累加

然後如果最後剩下的是偶數位數字就要繼續拆分,類似於迭代

是奇數位的話按位暴力即可

代碼:

#define ll long long
#include <iostream>
#include <cstdio>
using namespace std;
ll wei,n,ans,_[20][10],num[20],_10[20]={1},_45[20]={0,5,0,450};
int main()
{
	scanf("%lld",&n);
	for(int i=5;i<=17;i+=2) _45[i]=_45[i-2]*100;
	for(int i=1;i<=17;i++) _10[i]=_10[i-1]*10;
	for(int i=1;i<=17;i++)
		for(int j=0;j<=9;j++)
		{
			if(!j) _[i][j]=_[i-1][9];
			else if(i&1) _[i][j]=_[i][j-1]+_[i-1][9]+_10[i-1]*j;
			else _[i][j]=_[i][j-1]+_[i-1][9]-_10[i-1]*j;
		}
	for(int i=1;i<=17;i++)
	{
		if(_10[i]>n)
		{
			wei=i-1;
			break;
		}
		if(i&1) ans+=_45[i];
		else ans+=_[i][9]-_[i][0]; 
	}
	if(wei&1)
	{
		ll t=0,now=n;
		for(int i=1;i<=wei+1;i++)
		{
			num[i]=now%10;
			now/=10;
		}
		ans-=_[wei+1][0]; 
		for(int i=wei+1;i>=1;i--)
		{
			if(i==1) ans+=t*(num[i]+1)*_10[i-1]+_[i][num[i]];
			else if(num[i]&&i!=1) ans+=t*(num[i])*_10[i-1]+_[i][num[i]-1]; 
			if(i&1) t+=num[i];
			else t-=num[i];
		}
	}
	else
	{
		if(n&1) ans+=(n-_10[wei])/2+1;
		else
		{
			ans+=(n-_10[wei]+1)/2;
			ll now=n;
			for(int i=1;i<=17;i++)
			{
				if(!now) break;
				if(i&1) ans-=now%10;
				else ans+=now%10; 
				now/=10;
			}
		}
	}
	printf("%lld\n",ans);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章