• 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;
    }
    
  • 相关阅读:
    在SQL数据库中怎么去掉某一列的中的一写特殊字符
    PostgreSQL学习手册(常用数据类型)
    Oracle类型number与PG类型numeric对比和转换策略
    PostgreSQL数据库smallint、bigint转到Oracle,要用什么类型替代? 是number么,那长度分别是多少?
    Oracle中查看所有表和字段以及表注释.字段注释
    (转)不看绝对后悔的Linux三剑客之grep实战精讲
    (转)CentOS 6下配置软RAID图文详解
    (转)不看绝对后悔的Linux三剑客之sed实战精讲
    (转)CentOS 7常见的基础命令和配置
    (转)不看绝对后悔的Linux三剑客之awk实战精讲
  • 原文地址:https://www.cnblogs.com/AKMer/p/10027113.html
Copyright © 2020-2023  润新知