zoukankan      html  css  js  c++  java
  • 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,Mleqslant 10^5,|x_i|leqslant 10^9,Kleqslant 10^{18},a_iin[2,n-1],x_i)是整数。

    题解

    这种题目如果想到了就非常好做,可惜我想不到……

    假设现在要跳第(i)只兔子,那么(x_i=frac{1}{2} imes (2*x_{i-1}-x_i)+frac{1}{2} imes (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
    ",(double)ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    五子棋项目
    判断是否是素数
    双链表
    九九乘法表
    栈和队列
    c排序
    蓝桥杯 接水问题 模拟
    蓝桥杯 调和数列问题
    蓝桥杯 Hanoi问题 递归
    蓝桥杯 排列问题
  • 原文地址:https://www.cnblogs.com/AKMer/p/10027113.html
Copyright © 2011-2022 走看看