Rotate and Shift (USACO Bronze 2023 US Open)

Rotate and Shift (USACO Bronze 2023 US Open)

此题看似很复杂,牛跳来跳去,还有会移动的“活跃位置”。所以我们一步步来找规律。

首先,所题目所述,每过一分钟,所有的活跃位置AjA_j延圆圈转动一格。这时,如果我们集中注意力关注一头固定的牛,我们可以看到它永远是被同一个“活跃位置”覆盖的

假设一头牛开始的位置是ii,如果它“对应”的活跃位置是AjA_j,“对应”的意思是或者一开始Aj=iA_j=i,或者经过若干次转动之后AjA_j是第一个指向ii的活跃位置。 当iiAjA_j覆盖的时候,ii就会被转移到Aj+1modKA_{j+1\mod K}的位置。然后再次经过Aj+1modKAjA_{j+1 \mod K}-A_j分钟后,ii又会被AjA_j再次覆盖,重复这个过程。

所以ii的移动规律就是,从第一次被AjA_j覆盖开始,每次发生覆盖时向前移动Aj+1modKAjA_{j+1 \mod K}-A_j步,而因为所有AA在圆圈上同步移动,这个步长是一个固定位。

通过这个规律,我们就可以对这头牛O(1)\mathcal{O}(1)计算最终位置了,所以整体算法是O(N)\mathcal{O}(N)的。

#include <cstdio>
#include <algorithm>
#include <functional>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll;
typedef pair<int,int> pi;
 
int n, k, t;
int A[200005];
int ans[200005];
 
int main() {
    scanf("%d%d%d", &n, &k, &t);
    for (int i = 0; i < k; i++)
        scanf("%d", &A[i]);
 
    int j = 0;      // A1 == 0
    for (int i = 0; i < n; i++) {
        if (j < k-1 && i == A[j+1])
            j++;
        int t0 = i - A[j];
        int step = j == k-1 ? n-A[j] : A[j+1]-A[j];
        int times = 0;
        if (t >= t0)
            times = (t-t0 + step-1) / step;
        ans[(i + (ll)step * times) % n] = i;
    }
    for (int i = 0; i < n; i++)
        printf("%d ", ans[i]);
 
    return 0;
}