HDU 6034 Balala Power! 排序 貪心

鏈接

http://acm.hdu.edu.cn/showproblem.php?pid=6034

題意

給一組字符串,把每個字母變成[0,25] 中的一個數(不準有兩個字母變成的數相同),求這一組26進制數轉換成10進制後的最大和(不準出現前綴0),模1e7

思路

簡單的模擬題(寫寫這題蹭點訪問量2333)

比賽的時候sjt看完這題想到了思路,覺得我比較適合寫這種題(sjt,一個對此博客貢獻巨大的神犇,我只是他的偉大思想的記錄者,逃,2333,= =)

先標記出不能爲0的數,那些在長度大於1的字符串開頭的字母不能爲0。

然後用數組計算每個字母的權值,複雜度O(261e5) ,每個字母在某個位置,其對應的26進制數的某位就要多個1,用數組模擬這個數,然後從底位到高位把大於等於26的值進位,然後對這些數排序,顯然直接排序划不來,我們用一個cmp()把每個字母當作指針特殊處理下這個操作。

最後先把可以爲0的數中權值最小的數標記爲0,然後按權值從大到小決定每個字符的取值。

代碼:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define MS(x, y) memset(x, y, sizeof(x));

typedef long long LL;
const int MAXN = 1e5 + 5;
const int MOD = 1e9 + 7;

int n;
int head[MAXN], tail[MAXN];
int val[26];
int weights[26][MAXN], mx_len[26];
int arr[30];
char str[1000005];

bool cmp(int a, int b) {
  if (mx_len[a] != mx_len[b]) return mx_len[a] < mx_len[b];
  for (int i = mx_len[a]; i >= 0; --i) {
    if (weights[a][i] != weights[b][i]) return weights[a][i] < weights[b][i];
  }
  return false;
}

int main() {
  int kase = 0;
  while (~scanf("%d", &n)) {
    MS(val, -1);
    MS(mx_len, 0);
    for (int i = 0; i < 26; ++i) weights[i][0] = 0;
    for (int i = 1; i <= n; ++i) {
      head[i] = tail[i - 1];
      scanf("%s", str + head[i]);
      tail[i] = head[i] + strlen(str + head[i]);
      // 標記出不能爲0的數
      if (tail[i] - head[i] > 1) val[str[head[i]] - 'a'] = 1;
      for (int j = tail[i] - 1, k = 0; j >= head[i]; --j, ++k) {
        if (k > mx_len[str[j] - 'a']) {
          mx_len[str[j] - 'a'] = k;
          weights[str[j] - 'a'][k] = 0;
        }
        ++weights[str[j] - 'a'][k];
      }
    }
//    cout << str << endl;
    for (int i = 0; i < 26; ++i) {
      for (int j = 0; j <= mx_len[i]; ++j) {
        if (weights[i][j] >= 26) {
          if (j + 1 > mx_len[i]) {
            mx_len[i] = j + 1;
          }
          weights[i][j + 1] += weights[i][j] / 26;
          weights[i][j] %= 26;
        }
      }
    }
    for (int i = 0; i < 26; ++i) arr[i] = i;
    sort(arr, arr + 26, cmp);
    // 先決定哪個字母爲0
    for (int i = 0; i < 26; ++i) if (val[arr[i]] == -1) {
      val[arr[i]] = 0;
      break;
    }
    // 接着按權值決定每個字符的取值
    int cnt = 25;
    for (int i = 25; i >= 0; --i) if (val[arr[i]] != 0) val[arr[i]] = cnt--;
    LL ans = 0, tmp;
    for (int i = 1; i <= n; ++i) {
      tmp = 0;
      for (int j = head[i]; j < tail[i]; ++j) {
        (tmp *= 26) %= MOD;
        (tmp += val[str[j] - 'a']) %= MOD;
      }
      (ans += tmp) %= MOD;
    }
    printf("Case #%d: %I64d\n", ++kase, ans);
    // 最後一步清空,怕memset太慢了
    for (int i = 0; i < 26; ++i) for (int j = 0; j <= mx_len[i]; ++j) weights[i][j] = 0;
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章