HDU 6034 Balala Power! 排序 贪心

来源:互联网 发布:java deleteonexit 编辑:程序博客网 时间:2024/06/04 01:25

链接

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;  }}
原创粉丝点击