您的位置:首页 > 其它

【noip冲刺赛】:循环整数

2015-11-03 19:48 344 查看
【问题描述】

moreD 在学习完循环小数之后发现循环是个很美好的性质。自己只需要记住短短的循环

节以及循环次数(次数大于 1,且是整数)就可以记住整个数字了。

因为背诵数字变得方便了,moreD 决定背诵[L,R]内的所有循环的整数。moreD 的背诵

计划有 T 天,但是他不知道每天具体要背多少个数,请你帮助 moreD 计算出每天需要背诵

的数字个数。

如果 moreD 在某天遇到一个曾经背过的数字,他会义无反顾地重新背诵。

【输入格式】

第一行给出一个整数 T,表示 moreD 计划背诵 T 天的数字。

接下来 n 行,第 i 行给出 2 个整数 Li,Ri,表示 moreD 第 i 天的背诵计划。

【输出格式】

输出 T 行,每行一个整数,表示第 i 天 moreD 需要背诵的数字个数。

【输入输出样例】

circulate.in  circulate.out

3

1 10000

55555 66666

10 100

108

2

9

【数据范围】

对于 30%的数据 T*MAX{Ri}<=2*10^6

对于 70%的数据 MAX{Ri}<=2*10^6

对于 100%的数据 T<=50000,1<=Li<=Ri<=2*10^18

【样例解释】

对于第 2 天,moreD 只需要背诵 55555,66666.
对于第 3 天,moreD 只需要背诵 11,22,33,44,55,66,77,88,99.

把一个区间[l,r]分成两个区间[1,l][1,r],然后分别计算各区间的数量,最后用右边的区间减去左边的区间即可。

至于中间查找的过程= =。。。我能说是找规律吗。。

#include<cstdio>//将一个区间[l,r]分为[1,l]和[1,r]; 分别计算值 然后右边的减去左边的
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=19;

char a[20];
char b[20];
int n;
long long num[20];
long long sum[20];

void prepare()//初始
{
for(int i=1;i<maxn;i++)
{
long long p=9;
for(int j=1;j<i;j++,p*=10)
{

if(i%j==0)
{
sum[j]=p;
//	printf("%d\n",p);
for(int k=1;k<j;k++)
{
if(j%k==0)
{
sum[j]-=sum[k];//
}
}
num[i]+=sum[j];
//	printf("i=%d j=%d num=%lld sum=%lld\n",i,j,num[i],sum[j]);
}

}
}
}
long long init(char a[])//字符串转化为数字
{
long long rs=0;
int n=strlen(a);

for(int i=0;i<n;i++)
{
rs=rs*10+a[i]-'0';
}
return rs;
}
int count_num(long long x)
{
int d[maxn];
int p=0;//p即为位数
while(x>0)//将每一位存到d里面
{
d[++p]=x%10;
x/=10;
}
int ans=0;
for(int i=1;i<p;i++)
{
ans+=num[i];
//	printf("i=%d num=%lld ans=%d\n",i,num[i],ans);
}
long long s=1;
for(int j=1;j<p;j++,s*=10)
{
if(p%j==0)
{
long long t=0;
for(int i=p;i>p-j;i--)//
{
t=t*10+d[i];
//printf("t=%d\n",t);
}
long long q=0;
bool flag=false;
for(int i=p-j;i>0;i--)
{
//	printf("i=%d\n",i);
q=q*10+d[i];//
//	printf("%d\n",q);
if(i%j==1||j==1)
{
if(q<t)
{//printf("--------------");
flag=true;
}else if(q>t) break;
q=0;
}
}
sum[j]=t-s-flag+1;
//	printf("j=%d orz=%d\n",j,sum[j]);
for(int k=1;k<j;k++)
{
if(j%k==0)
{
sum[j]-=sum[k];
}
}
ans+=sum[j];
}
}
return ans;
}
int main()
{
freopen("circulate.in", "r", stdin);
freopen("circulate.out", "w", stdout);
prepare();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s %s",a,b);
long long sb1=init(a);
long long sb2=init(b);
//	printf("%lld %lld\n",sb1,sb2);
long long ans=count_num(sb2)-count_num(sb1-1);
//printf("sb2=%d sb1=%d\n",count_num(sb2),count_num(sb1));
printf("%lld\n",ans);
}
return 0;
}
/*
求一个数字区间内有循环节的数字个数:
input:
3
1 10000
55555 66666
10 100

output:
108
2
9
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: