牛客练习赛1 C - 圈圈

链接:https://www.nowcoder.com/acm/contest/2/C
来源:牛客网

题目描述

shy有一个队列a[1], a[2],…,a[n]。现在我们不停地把头上的元素放到尾巴上。在这过程中我们会得到n个不同的队列,每个队列都是a[k],a[k+1],…,a[n],a[1],…,a[k-1]的形式。在这些队列中,我们可以找到字典序最小的。
shy无聊的时候会给队列的每个元素加一玩。但是为了使得游戏不这么无聊,shy加一以后会给每个元素模m,这样子字典序最小的序列就会变了,生活就变得有趣。
很显然这样子加m次以后,序列会变成原来的样子。所以现在shy想知道,在他没有加一前,加一时,加二时,….,加m-1时字典序最小的序列的第k(和上面的k没有关系)个元素分别是几。

输入描述:

第一行三个整数n,m,k表示序列长度,取模的数和要求的序列的第几个元素。
接下来一行n个整数表示初始序列。

输出描述:

m个整数表示答案。
示例1

输入

5 6 3
1 2 1 2 3

输出

1
2
3
5
5
0

备注:

对于30%的数据,1≤n,m≤100;
对于100%的数据,1≤n,m≤50000, 1≤k≤n, 0≤a[i]<m;

题解

字符串$hash$。

每个数字都会变且仅变一次零。

如果上一次到这一次没有零产生,那么答案的位置不会改变。

否则重新寻找答案产生的位置。

两个字符串比较字典序,字符串$hash$一下,找$lcp$即可。

#include<bits/stdc++.h>
using namespace std;

long long mod[2];
long long base[2];
const int maxn = 1e5 + 10;
int a[maxn], n, m, k;
long long h[2][maxn];
long long b[2][maxn];
int ans[maxn];
vector<int> g[maxn];

void init() {
  mod[0] = 1e9 + 7;
  mod[1] = 1e9 + 7;
  base[0] = 131LL;
  base[1] = 313LL;
  b[0][0] = b[1][0] = 1LL;
  for(int i = 1; i < maxn; i ++) {
    for(int t = 0; t < 2; t ++) {
      b[t][i] = b[t][i - 1] * base[t] % mod[t];
    }
  }
}

int check(int x, int y, int len) {
  if(len == 0) return 1;
  if(x > y) swap(x, y);
  for(int t = 0; t < 2; t ++) {
    long long AA = 0, BB = 0;
    if(x > 0) AA = h[t][x - 1] * b[t][len] % mod[t];
    if(y > 0) BB = h[t][y - 1] * b[t][len] % mod[t];
    long long A = (h[t][x + len - 1] - AA + mod[t]) % mod[t];
    long long B = (h[t][y + len - 1] - BB + mod[t]) % mod[t];
    if(A != B) return 0;
  }
  return 1;
}

int ok(int x, int y, int f) {
  int L = 0, R = n, pos = -1;
  while(L <= R) {
    int mid = (L + R) / 2;
    if(check(x, y, mid)) pos = mid, L = mid + 1;
    else R = mid - 1;
  }
  if(pos == n) return 0;
  if((a[x + pos] + f) % m
   < (a[y + pos] + f) % m) return 1;
  return 0;
}

int main() {
  init();
  scanf("%d%d%d", &n, &m, &k);
  k --;
  long long A[2];
  A[0] = A[1] = 0;
  for(int i = 0; i < n; i ++) {
    scanf("%d", &a[i]);
    a[i + n] = a[i];
    g[(m - a[i]) % m].push_back(i);
  }
  for(int i = 0; i < 2 * n; i ++) {
    for(int t = 0; t < 2; t ++) {
      A[t] = A[t] * base[t] % mod[t];
      A[t] = (A[t] + a[i]) % mod[t];
      h[t][i] = A[t];
    }
  }
  
  int p = 0;
  for(int i = 1; i < n; i ++) {
    if(ok(i, p, 0)) p = i;
  }
  ans[0] = a[p + k];
  for(int i = 1; i < m; i ++) {
    if(g[i].size() == 0) {
      ans[i] = ans[i - 1] + 1;
    } else {
      p = g[i][0];
      for(int j = 1; j < g[i].size(); j ++) {
        if(ok(g[i][j], p, i)) p = g[i][j];
      }
      ans[i] = (a[p + k] + i) % m;
    }
  }
  for(int i = 0; i < m; i ++) {
    printf("%d\n", ans[i]);
  }
  return 0;
}

 

posted @ 2018-01-26 17:26  Fighting_Heart  阅读(394)  评论(0编辑  收藏  举报