定義迴文串爲正着讀反着讀都同樣的數字串,若是一個數字串的一個長度大於 \(1\) 的子串也爲迴文串的話,那麼咱們也定義這個數字串爲迴文串。ios
因此不是迴文串的數字爲非迴文串,求區間 \([l, r]\) 內有多少個非迴文串 ,數據範圍: \(0 \le l \le r \le 10^{18}\)數組
設 \(f[i][j][k]\) 表示長度爲 \(i\) 最高位爲 \(j\) 次高位爲 \(k\) 的非迴文串的個數函數
由於只要知足子串是迴文數它就是迴文串,因此判斷比較的時候只須要與前兩位數比較就好啦spa
轉移方程:code
實際意義:表示區間 \([jk000\cdots,jk999\cdots]\) 的非迴文數的和ci
對於求 \(ans_{l, r}\) 能夠轉化爲 \(ans_{1, r} - ans_{1, l - 1}\)get
求 \(ans_{l,r}\) 時的策略:string
設 \(len\) 爲 \(r\) 的位數,\(a[len]\) 中存 \(r\) 的每一位it
一、對於全部長度小於 \(len\) 的 \(f\) , \(ans += \sum_{1 \le j \le 9}^{2 \le i \le len - 1} f[i][j][k](0 \le k \le 9)\)io
二、對於長度小於等於 \(len\) 位且最高位小於 \(a[i]\) 的 \(f\),\(ans += f[i][j][k] (0 \le k \le 9)\) ,加的過程當中注意判斷此時是不是非迴文串
三、由於 \(2\) 枚舉不到最後的個位數,因此要在最後單獨判斷一遍
本人在理解上的一個很傻逼的誤區:
主函數最後的那個 \(for\) 循環是判斷 \(l\) 是不是非迴文串,由於前面已經求了 \(ans_{1, r}\) 和 \(ans_{1, l}\) ,二者相減所求區間是 \(ans_{l + 1, r}\) 並無取到 \(l\) ,按理說執行 \(solve(l - 1)\) 是能夠解決的,但由於這裏用的字符數組讀入,因此不免有鍋(我爲這理解了一下午)
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<string> #include<cstring> #define LL long long using namespace std; const int MAXN = 1010; LL read(){ LL s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar(); return s * w; } char l[MAXN], r[MAXN]; LL f[MAXN][13][13]; LL a[MAXN]; void init(){ for(int i = 2; i <= 1001; ++i){ for(int j = 0; j <= 9; ++j){ for(int k = 0; k <= 9; ++k){ if(j == k) continue;//若是相鄰兩個元素同樣,那麼必定是迴文串,直接跳過 for(int a = 0; a <= 9; ++a){ if(j != a && a != k)//若是不是2迴文也不是3迴文 f[i][j][k] += f[i - 1][k][a]; } if(i == 2) f[i][j][k]++;//若是長度爲2,必定不是 } } } } LL solve(char s[]){ memset(a, 0, sizeof(a)); LL tot = 0; bool t = 1; int len = strlen(s); LL ans = 0, last1 = -1, last2 = -1, sum = 0; for(int i = len; i >= 1; --i){ a[i] = s[len - i] - '0';//把個位放前面 sum = (sum << 1) + (sum << 3) + a[i];// } if(len == 1) return sum + 1;//若是長度爲1,那麼不用判斷了 ans += 10;//算上長度爲1的那10個數 for(int i = 2; i < len; ++i){//老套路把滿着的先加上 for(int j = 1; j <= 9; ++j){ for(int k = 0; k <= 9; ++k){ ans = ans + f[i][j][k]; } } } for(int i = len; i >= 2; i--){ for(int j = 0; j < a[i]; ++j){ if(i == len && j == 0) continue;//首位是0就跳過 for(int k = 0; k <= 9; ++k){ if(last1 != j && last2 != j && j != k && last1 != k){ ans = ans + f[i][j][k]; } } } if(last1 == a[i] || last2 == a[i]) {//上一位和上兩位 t = 0; break; } last2 = last1, last1 = a[i];//更新 } if(t) {//若是沒有中途退出 for(int i = 0; i <= a[1]; ++i){//最後一位剩下的那一點 if(i != last1 && i != last2) ans++; } } return ans; } int main() { init(); cin >> l >> r; LL ans = solve(r) - solve(l); int t = strlen(l), flag = 0; for(int i = 1; i < t; ++i){ if(l[i] == l[i - 1] || (l[i] == l[i - 2] && i > 1)) { flag = 1; break; } } if(!flag) ans++; printf("%lld", ans); return 0; }