1. 程式人生 > >AtCoder Grand Contest 006 C:Rabbit Exercise

AtCoder Grand Contest 006 C:Rabbit Exercise

題目傳送門:https://agc006.contest.atcoder.jp/tasks/agc006_c

題目翻譯

數軸上有\(N\)只兔子,從\(1\)\(N\)編號,每隻兔子初始位置是\(x_i\)。現在兔子們要開始做運動,運動都有\(M\)個步驟,對於第\(i\)個步驟,我們用\(a_i\)來形容它,意思是:

在當前步驟中,從左至右數第\(a_i\)只兔子將會跳躍。我們在\(a_i-1\)\(a_i+1\)兩隻兔子中等概率的選擇一個兔子,假設我們選擇的是\(x\),那麼第\(a_i\)只兔子將會跳到數軸上關於\(x\)只兔子的座標對稱的另一個點上。

比如第\(a_i\)只兔子座標為\(3\)

,第\(x\)只兔子座標為\(5\),那麼第\(a_i\)只兔子就會跳到\(7\)去。

接下來兔子們要做\(K\)輪這樣的運動,請求出最後每個兔子所在座標的期望。

\(N,M\leqslant 10^5,|x_i|\leqslant 10^9,K\leqslant 10^{18},a_i\in[2,n-1],x_i\)是整數。

題解

這種題目如果想到了就非常好做,可惜我想不到……

假設現在要跳第\(i\)只兔子,那麼\(x_i=\frac{1}{2}\times (2*x_{i-1}-x_i)+\frac{1}{2}\times (2*x_{i+1}-x_i)=x_{i-1}+x_{i+1}-x_i\)

原本這三隻兔子分別在:\(x_{i-1},x_i,x_{i+1}\)

現在這三隻兔子分別在:\(x_{i-1},x_{i-1}+x_{i+1}-x_i,x_{i+1}\)

看起來怪怪的,上下長度不一,所以我們把這倆序列差分一下。

原本三隻兔子座標差分序列:\(x_{i-1},x_i-x_{i-1},x_{i+1}-x_i\)

現在三隻兔子座標差分序列:\(x_{i-1},x_{i+1}-x_i,x_i-x_{i-1}\)

然後我們發現對於一次跳躍,只是交換了差分陣列的兩個位置而已……

也就是說,我們可以求出在\(M\)個步驟後差分陣列的置換,然後根據置換求出每個位置在\(K\)

輪運動之後最後是原陣列的哪個元素,最後字首和加起來就是答案了。

時間複雜度:\(O(N+M)\)

空間複雜度:\(O(N)\)

程式碼如下:

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;

const int maxn=1e5+5;

ll k;
int n,m;
int c[maxn];
bool bo[maxn];
ll a[maxn],ans[maxn];//-1e9關於1e9對稱就直接爆int了

int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

int main() {
    n=read();
    for(int i=1;i<=n;i++)
        scanf("%lld",a+i),c[i]=i;
    m=read();scanf("%lld",&k);
    for(int i=1;i<=m;i++) {
        int x=read();
        swap(c[x],c[x+1]);
    }
    for(int i=1;i<=n;i++)
        if(!bo[i]) {
            int u=i,cnt=0,step,goal;
            while(!bo[c[u]])
                bo[c[u]]=1,cnt++,u=c[u];//求迴圈節大小
            step=k%cnt,goal=u=i;
            for(int j=1;j<=step;j++)
                goal=c[goal];
            for(int j=1;j<=cnt;j++)
                ans[u]=goal,u=c[u],goal=c[goal];//u和goal相差step步
        }
    for(int i=2;i<=n;i++) {
        int x=ans[i];
        ans[i]=a[x]-a[x-1];
    }
    ans[1]=a[1];
    for(int i=1;i<=n;i++)
        ans[i]+=ans[i-1],printf("%.1lf\n",(double)ans[i]);
    return 0;
}