题目描述
你曾经因为看见一样的东西一遍又一遍地重复、循环而对电视节目感到厌烦么?好吧,虽然我并不关心电视节目的好坏,不过有时却也很像那样不断循环的数字。
让我们假定两个不同的正整数 (n,m) 是循环的,当且仅当你能通过将 n 末端的几个数字移到它的首端而不改变移动的数字的顺序并使整个数字变成 m 。举个例子,(12345,34512) 就是一对循环的数字,因为你能把 12345 中末尾的 345 移到 12 前面,从而得到 34512。注意,为了成为一对循环的数字,n 和 m 位数必须相同。无论 n 或 m 都没有前置的 0。
现在给定正整数 A 和 B,并保证 A 和 B 位数相同且均没有前置 0,求存在多少循环的正整数对 (n,m),使得 A≤n≤m≤B ?
输入格式
本题有共有 10 个测试点。 每个输入文件包含 1 行。 第 1 行有两个用空格隔开的正整数 A 和 B。
输出格式
每个输出文件应包含一个正整数 x,表示共有 x 组循环的正整数对 (n,m) 使得 A≤n≤m≤B。
输入输出样例
输入 #1
1111 2222
输出 #1
287
说明/提示
1≤A,B≤2×10^6。
思路
模拟可过。
对于题目中描述的几个操作,分别解决,然后直接调用即可得到答案。
-
我们可以选择把数字转换成字符串处理。(
其实是不想去想怎么循环数字)数字转字符串很简单,可以直接用一个
while
循环解决。代码如下:
while(k)s[l++]=k%10+'0',k/=10;
这样我们是倒序存入的,所以字符串转数字稍微麻烦一点:
inline int toi(int l){ R int k=0; for(R int i=l-1;i>=0;i--) k=k*10+s[i]-'0'; return k; }
-
现在对于循环进行处理。
注意:1. 数字首位不为零,如果为零就继续下一个。
2. 这里的循环按照题目定义,不能用
next_permutation
inline int nxt(int l,int k){ s[l]=s[0]; for(R int i=0;i<l;i++)s[i]=s[i+1]; if(s[0]==0)return nxt(l,k); if(toi(l)!=k)return 1; return 0; }
-
按照题目描述,从 �A 到 �B 枚举每一个数字,判断能够组成多少个符合要求的正整数对。
inline int ck(int k){ R int l=0,t,f=k; while(k)s[l++]=k%10+'0',k/=10; while(nxt(l,f)){ t=toi(l); if(t>f&&t<=m&&!vis[t])++k; } return k; }
完整代码
#include <bits/stdc++.h>
using namespace std;
int n,m,ans;
bool vis[2000001];
char s[100];
int read(){
int x=0;
char c=getchar();
//freopen("a.in","r",stdin);
while(c>'9'||c<'0')c=getchar();
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
//freopen("b.in","r",stdin);
}
return x;
}
int toi(int l){
int k=0;
for(int i=l-1;i>=0;i--)k=k*10+s[i]-'0';
return k;
}
int next(int l,int k){
s[l]=s[0];
for(int i=0;i<l;i++)s[i]=s[i+1];
if(s[0]==0)return next(l,k);
if(toi(l)!=k)return 1;
return 0;
}
int ck(int k){
int l=0,t,f=k;
while(k)s[l++]=k%10+'0',k/=10;
while(next(l,f)){
t=toi(l);
if(t>f&&t<=m&&!vis[t])++k;
}
return k;
}
int main(){
n=read();
m=read();
for(int i=n;i<=m;i++){
vis[i]=1;
ans+=ck(i);
}
cout<<ans<<endl;
//freopen("c.out","w",stdout);
return 0;
}