hiho1622 有趣的子區間(YY)

 

題目連接:http://hihocoder.com/problemset/problem/1622?sid=1230113ios

#1622 : 有趣的子區間

時間限制:10000ms
單點時限:1000ms
內存限制:256MB

描述

若是一個區間[a, b]內剛好包含偶數個迴文整數,咱們就稱[a, b]是有趣的區間。  優化

例如[9, 12]包含兩個迴文整數9和11,因此[9, 12]是有趣的區間。[12, 20]包含0個迴文整數,因此[12, 20]也是有趣的。  spa

如今給定一個區間[a, b],請你求出[a, b]中全部知足a ≤ p ≤ q ≤ b的子區間[p, q]有多少個有趣的。code

輸入

第一行包含兩個整數a和b。  blog

對於30%的數據,1 ≤ a ≤ b ≤ 1000  排序

對於60%的數據,1 ≤ a ≤ b ≤ 100000  內存

對於100%的數據, 1 ≤ a ≤ b ≤ 1000000000ci

輸出

有趣的子區間數目get

樣例輸入
10 20
樣例輸出
46

 

菜ji題解,大牛請略過。。。string

 

剛看到題目是半點思路也沒有啊,要統計全部區間(10^9)^2,還要計算區間內迴文數的個數。這。。玩不了。(手動捂臉。。

 

可是仔細一想特麼即使區間大小長達1e9,可是1e9內的迴文數很少啊(由於前一半肯定了,後一半也就肯定了= = ),估算一下差很少在1e5個迴文數左右。。因而很瓜熟蒂落的預處理1e9內的全部迴文數並排序。。。(可是有什麼用呢= =)

 

若是每兩個迴文數當作一個區間,計算有趣區間個數。好比a, b, c, d, e五個迴文數(從小到大),那麼考慮左端點在(a, b]、右端點在(c, d]的全部區間都是有趣的,這樣的計算複雜度是O(1)的。[有趣區間數=(b - a) * (d - c)],這樣只要枚舉迴文數個數爲偶數的全部迴文數區間

好比加入上述例子中區間爲[l, r] 且 l < a, r > e, 那麼枚舉有趣的區間的:

1.左端點在[l, a],右端點在[b, c)             // 區間內有兩個迴文數

2.左端點在[l, a],右端點在[d, e)             // 區間內有四個迴文數

3.左端點在(a, b],右端點在[c, d)           // ...

4.左端點在(a, b],右端點在[e, r]           // ...

5.左端點在(b, c],右端點在[d, e)           // ...

...

對於每一個枚舉都是保證區間內迴文數爲偶數的前提下,計算左端點可取的個數x(好比樣例1:x=a - l + 1), 右端點可取的個數y(好比樣例1:y=c - b),那麼這次枚舉的有趣的區間數爲x * y。最後對全部的x * y求和(即上面的枚舉狀況1.2.3.4.5....全部的x * y求和)便可。能夠看到這樣的複雜度爲O(1e5 ^ 2)=O(1e10),複雜度減小了很多,可是仍是接受不了啊= =

 

還要優化。。。

那。。繼續來。。。

 

相信細心的讀者已經注意到了,在上面的例子中狀況2和狀況5枚舉了同一個右邊界的狀況[d, e),緣由在於他們的左邊界[l, a]和(b, c]這兩個區間之間始終差距兩個(偶數個)迴文數,而狀況1中右邊界爲[b,c),與狀況5的左邊界一致,那麼在計算狀況一、二、5時,即可以統一處理:

首先計算區間[b, c)和區間[d, e)的長度和(差距爲偶數的區間長度和):

        sum = (c - b) + (e - d) // + (g - f) + ...

那麼狀況1和狀況2能夠合併爲

        ans += (a - l + 1) * sum (其實這個表明全部有趣的區間的左端點落在[l, a]的方法)

在計算狀況5時:

        首先令sum -= c - b

        ans += (c - b) * sum(其實這個表明全部有趣的區間的左端點落在(b, c]的方法)

好啦,複雜度順利降到了O(1e5)

至於代碼什麼的,個人一貫可讀性不高啦。。有了思路應該均可以搞得定~(只是大神分分鐘,蒟蒻我花了一整晚T_T)

 

順便說一句,個人代碼思路是[l, r]全部區間數減去非有趣的區間數計算的,由於不要忘了一個迴文數沒有的區間也是有趣的區間,也就是上面的左右端點都在[l, a)的區間也是有趣的。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <vector>
  5 #include <queue>
  6 #include <algorithm>
  7 using namespace std;
  8 
  9 typedef long long LL;
 10 
 11 const int N = 1000005;
 12 const int M = 1000000000;
 13 
 14 int hwNums[N], cntHW;
 15 
 16 int rever(int n)
 17 {
 18     int ans = 0;
 19     while(n)
 20     {
 21         ans = ans * 10 + n % 10;
 22         n /= 10;
 23     }
 24     return ans;
 25 }
 26 
 27 int getLenP(int n)
 28 {
 29     int ans = 1;
 30     while(n) ans *= 10, n /= 10;
 31     return ans;
 32 }
 33 
 34 void init()
 35 {
 36     for(int i = 1; i < 10000; i ++)
 37     {
 38         if(i < 10) hwNums[cntHW ++] = i;
 39 
 40         int r = rever(i), p = getLenP(i);
 41         hwNums[cntHW ++] = i * p + r;
 42 
 43         for (int j = 0; j < 10; j ++)
 44         {
 45             LL num = (LL)i * 10 * p + j * p + r;
 46             if(num <= M) hwNums[cntHW ++] = num;
 47         }
 48     }
 49     // 隨意添加兩個更大的數,能夠略去後面的邊界狀況討論
 50     hwNums[cntHW ++] = 1000000001;
 51     hwNums[cntHW ++] = 1100000011;
 52     sort(hwNums, hwNums + cntHW);
 53 }
 54 
 55 // 對於l, hw1, hw2, hw3, ..., r
 56 // 計算有趣的區間的左端點落在[l, hw1], (hw2, hw3], (hw4, hw5] ... 的全部的方法數
 57 LL count_ans(int l, int r)
 58 {
 59     int id = 0, tid;
 60     while(hwNums[id] <= l) id ++; // while中略去了id < cntHW,由於上面添加了兩個超出邊界的數
 61     if(hwNums[id] > r) return 0;
 62     tid = id;
 63 
 64     LL sum = 0, pre = hwNums[id ++];
 65     while(hwNums[id] <= r)
 66     {
 67         sum += hwNums[id] - pre;
 68         pre = hwNums[++ id];
 69         id ++;
 70     }
 71     if(pre <= r) sum += r + 1 - pre;
 72 
 73     LL ans = 0;
 74     pre = l;
 75     while(hwNums[tid] <= r)
 76     {
 77         ans += (hwNums[tid] - pre) * sum;
 78         sum -= hwNums[tid + 1] - hwNums[tid];
 79         pre = hwNums[++tid];
 80         tid ++;
 81     }
 82     return ans;
 83 }
 84 
 85 int main()
 86 {
 87     //freopen("in.txt", "r", stdin);
 88 
 89     init();
 90 
 91     int a, b;
 92     cin >> a >> b;
 93     a --;
 94 
 95     LL n = b - a, ans = n * (n + 1) / 2;
 96 
 97     int id = 0;
 98     while(hwNums[id] <= a) id ++;
 99 
100     ans -= count_ans(a, b) + count_ans(hwNums[id], b);
101 
102     cout << ans << endl;
103 
104     return 0;
105 }
相關文章
相關標籤/搜索