空間限制:C/C++ 32768K,其他語言65536K
64bit IO Format: %lld
題目描述
輸入描述:
輸出描述:
每組數據輸出結果,並換行。
輸入
11 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 1 100
輸出
0 0 0 1 0 1 0 2 1 1 111
備註:
數字的圈的個數請根據樣例自行理解。
題意:0這個數字是一個圈,同樣的,4,6,9,都是一個圈,8是兩個圈,其他數字沒有圈,樣例給的很清楚。
思路:前兩天做過一道類似的題,跟這個做法一模一樣(https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1042)。
先統計a到b這個區間(0-9)每個數字出現的個數,最後計算每個數字的貢獻。
現在問題是求每個數字出現了多少次。
舉個栗子:55211這個帶下劃線的位置出現了多少次的2(在1到55211這些數字中)
答案是55*100+11+1次 及(0-54)2(00-99),還有552(00-11);這個應該能看懂。
那如果統計這個位置3出現的次數呢? 答案是:55*100次 。 及(0-54)3(00-99) 553(..)沒有這樣的數字
那如果統計這個位置1出現的次數呢? 答案是:56*100次 。 及(0-55)1(00-99)
那麼這樣你就能統計這個位置可能出現的0-9這些數字各出現了多少次了,那麼你再枚舉每一個位置即可,複雜度就是9*(這個數字的位數)。
還有一種特殊情況:0的次數可能有偏差(因爲沒有前導0的存在)
舉個栗子:5000這個帶下劃線的位置出現了多少次的0(在1到1000這些數字中)
如果按照上面的規則計算的話,是5*100+1 次。 及(0-4)0(0-99)和50(00-00)顯然前面爲0的100次是不存在的(及00(00-99)),所以要減去這種情況。0出現的次數:個位減去1,十位減去10,百位減去100,以此類推。
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<math.h>
#include<vector>
#include<queue>
#include<algorithm>
#define LL long long
#define N 50050
const LL mod=1e9+7;
using namespace std;
int v[20]= {1,0,0,0,1,0,1,0,2,1};
LL s[15];
void slove(LL x,int flag)
{
LL sum=1,qian,zhong,hou;
while(1)
{
qian=x/sum/10;
zhong=x/sum%10;
hou=x%sum;
if(hou==x) break;
for(int i=0; i<10; i++)
{
if(i<zhong) s[i]+=(qian+1)*sum*flag;
else if(i==zhong) s[i]+=(qian*sum+hou+1)*flag;
else if(i>zhong) s[i]+=(qian*sum)*flag;
}
s[0]-=sum*flag;
sum*=10;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(s,0,sizeof s);
LL a,b;
scanf("%lld%lld",&a,&b);
slove(b,1);
slove(a-1,-1);
LL ans=0;
for(int i=0; i<10; i++)
ans+=v[i]*s[i];
printf("%lld\n",ans);
}
}