您的位置:首页 > 其它

XJOI NOIP16提高组赛前训练18-day2 T1:友好数对(数论)

2016-11-15 13:01 309 查看

XJOI NOIP16提高组赛前训练18-day2 T1:友好数对

题目描述:

如果一个数a能由一个数b旋转得到,那么我们称< a,b >为友好数对,如12345和45123为友好数对,12345和54321不为友好数对.给出两个正整数L,R,求有多少友好数对< a,b >,满足L<=a

输入格式:

第一行一个整数T,表示数据组数,每组数据两个正整数L,R.

输出格式:

对于每组数据,输出一个整数表示答案.

样例输入:

4

1 9

10 40

100 500

1111 2222

样例输出:

0

3

156

287

数据范围:

对于30%的数据满足L,R<=1000

对于100%的数据满足L,R<=2000000,T<=30,L,R位数相同。

时间限制:

2S

空间限制:

256M

题目分析:

(感觉题目描述有毒,完全没看出来他想说什么样的数对是友好数对)

先解释一下友好数对是什么,先把数理解成一个字符环,那么从某处切开形成的数就是他的友好数,例如1735可以变成7351,3517,5173,那么实际上这几个数都互为友好数对.那么对于一个数来说,他的友好数集合是一定的,而且只要两个数不互为友好数,那么他们的友好数集合一定不相交.由此可以通过一个数,求出他的集合,并记录形成的友好数对,这样对于每一个数都只会判断一次,且答案不会有重复的数对.

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long ll;
const int maxn=2000000+10;

int read()
{
char ch=getchar();int ret=0,flag=1;
while(ch<'0'||ch>'9') {if(ch=='-') flag=-1; ch=getchar();}
while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*flag;
}

int c10[10];

void init()
{
c10[0]=1;
for(int i=1;i<=8;i++) c10[i]=c10[i-1]*10;
}

int degit(int n)//计算n的数位
{
if(n==0) return 1;
int l=0;
while(n>0) n/=10,++l;
return l;
}

ll ans;
int vis[maxn],L,R;

void count(int n)//对于每一个友好数集合的计算
{
vis
=1;
int l=degit(n),cnt=0;
for(int i=1;i<l;i++) {
int t=n/c10[i]+n%c10[i]*c10[l-i];
if(t>=L&&t<=R&&!vis[t]) vis[t]=1,ans+=++cnt;//判断现在生成的这一个友好数是否被算过,还要考虑t是否在[L,R]的范围内.对于新的一个数可以与前面所有数形成友好数对,对于答案的贡献是cnt
}
}

ll slove()
{
ans=0;
for(int i=L;i<=R;i++) if(!vis[i]) count(i);//如果该数未被标记,则其集合一定未被计算过
for(int i=L;i<=R;i++) vis[i]=0;//多组数据,标记清除
return ans;
}

int main()
{
init();
int T=read();
while(T--) {
L=read(),R=read();
printf("%lld\n",slove());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: