奇怪數(odometer)
【題目描述】
一個正整數Z是奇怪數,當且僅當滿足的條件是:Z的所有數字中,只有一個數字不同於其他數字。例如:33323、110 都是奇怪數,而 9779、5555 都不是奇怪數。給出兩個正整數 X 和 Y,滿足 100 <= X <= Y <= 10^16,請問區間[X,Y]內有多少個奇怪數?
【輸入格式】odometer.in
一行,兩個整數,X 和 Y。
【輸出格式】odometer.out
一個整數。【輸入樣例】
110 133
【輸出樣例】
13
【樣例解釋】
110,112,113,114,115,116,117,118,119,121,122,131,133 都是奇怪數。
【解題思路】
基本思路是枚舉,但是如果按照正常方法進行枚舉,那麼依照本題的數據範圍,必然會超過時間限制。顯然,需要另外尋找一條路進行枚舉。
根據題面可知,奇怪數是由a,b兩個數字組成,但是其中b只能出現一次。所以,我們可以嘗試枚舉a和b,構成奇怪數。在構成奇怪數之後,判斷是否在x和y的範圍內即可。
【解題反思】
- 可以嘗試從問題的另一面入手解決問題。
- 注意奇怪數的定義,由兩個數字組成,但是其中有一個數字只能出現一次,9559,633663這些就不是奇怪數。
【參考程序】
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long len,x,y;
long long count(long long num)
{
string st="",s="";
int ansc=0;
while (num!=0)
{
st=char(num%10+48)+st;
num/=10;
}//將數字轉化爲字符串 以便求出長度
len=st.size();
for (int i=3;i<=len;i++)//枚舉奇怪數的長度
for (char j='0';j<='9';j++)//枚舉奇怪數中重複出現的數字
{
s="";
for (int k=0;k<i;k++) s+=j;//填充奇怪數
for (char l='0';l<='9';l++)//枚舉奇怪數中只出現一次的數字
if (j!=l)//兩數不相同纔有意義
for (int m=0;m<i;m++)//枚舉奇怪數中只出現一次的數字的位置
{
s[m]=l;//填充
if (s[0]!='0'&& (s<=st||i<len)) ansc++;//判斷是否在範圍內
s[m]=j;
}
}
return ansc;
}
int main()
{
freopen("odometer.in","r",stdin);
freopen("odometer.out","w",stdout);
cin>>x>>y;
cout<<count(y)-count(x-1);//利用子程序求出100~y之間的奇怪數,再求出 100~(x-1)的奇怪數
//兩者相減即爲x~y的奇怪數
return 0;
}