Luogu1112 波浪数 转自www.luogu.org
题目描述
波浪数是在一对数字之间交替转换的数,如1212121,双重波浪数则是指在两种进制下都是波浪数的数,如十进制数191919是一个十进制下的波浪数,它对应的十一进制数121212也是一个波浪数,所以十进制数191919是一个双重波浪数。
类似的可以定义三重波浪数,三重波浪数在三种不同的进制中都是波浪数,甚至还有四重波浪数,如十进制300=606(七进制)=363(九进制)=454(八进制)=1A1(十三进制)…,你的任务就是在指定范围内找出双重、三重、四重波浪数。
输入输出格式
输入格式:
单独一行包含五个用空格隔开的十进制整数,前两个数表示进制的范围(2••32),第三与第四个数表示指定的范围(1••10000000),第五个数为2,3,4中的一个,表示要找的波浪数的重数。
输出格式:
从小到大以十进制形式输出指定范围内的指定重数的波浪数。一行输出一个数。
输入样例:
10 11 190000 960000 2
输出样例:
191919
383838
575757
767676
959595
题目大意:
题目要求在规定范围内寻找多重波浪数。波浪数是用两位不同的数字间相互交替的数。x重波浪数就是一个数在其他的进制里有且仅有x个波浪数。
分析:
看到波浪数的每个部分以循环出现,就瞬间怂了,但是仔细看看,是每对数字循环出现,也就是说只有两个数字循环,这样我们就可以枚举每两个数,再枚举长度可以构造一个波浪数,再用hash的方法判断是几重波浪数。题目范围1~10000000,进制范围2~32如果每个数暴搜过去时间就至少是O(10^8)再加上判断各个进制波浪数的时间,肯定是要超时。这时就要预处理,找到这个范围内的进制最短的长度和最长的长度,在这里面枚举。效率就会大大增加。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <bitset>
#include <ctime>
#include <set>
#include <sstream>
#include <vector>
#include <map>
#include <algorithm>
#include <queue>
using namespace std;
int a,b,R,L,cs;
long hash[10000005];
bool h[33][33][33][100];
long l(int jz,int s)
{
int sum=1;
while (s/jz)
{
s/=jz;
sum++;
}
return sum;
}
long bls(int jz,int length,int s1,int s2)
{
int num=s1;
for (int i=1;i<length;i++)
{
if (i%2) num=num*jz+s2;
else num=num*jz+s1;
}
return num;
}
/*
举例
A1A1(16)
1*1+10*16+1*16*16=1+160+256
1*16^0+A*16^1+1*16^2+A*16^3
=1*16^0+16^1*(A+1*16^1+A*16^2)
=1*16^0+16^1*(A+16^1*(1+A*16^1))
=1+16^1*(A+16^1*(1+A*16^1))
bls(jz,length,s1,s2)=s2+jz*(s1+jz*(s2+jz*(…)))
*/
void Solve(int jz)
{
int l1,l2;
l1=l(jz,L);l2=l(jz,R);
for (int i=l1;i<=l2;i++)
{
for (int j=1;j<jz;j++)
for (int k=0;k<jz;k++)
{
if (h[j][k][jz][i]||h[k][j][jz][i]||j==k) continue;
long number=bls(jz,i,j,k);
if (number>=L&&number<=R)
{
hash[number]+=2;
h[j][k][jz][i]=false;
h[k][j][jz][i]=false;
}
else if (number>R) break;//如果算第二位超过范围 接下来的就都超过范围了
}
}
}
void init ()
{
cin>>a>>b>>L>>R>>cs;
for (int i=a;i<=b;i++)
Solve(i);
}
int main()
{
init ();
for (int i=L;i<=R;i++) if (hash[i]==cs) cout<<i<<endl;;
return 0;
}