zoukankan      html  css  js  c++  java
  • 题解 P6148 【[USACO20FEB]Swapity Swapity Swap S】

    前言

    考场上没想到用倍增,呜呜呜~,只写了个找循环节,然后就 (30) 分。

    正文

    分析

    考虑用倍增,其实这道题和这道题是有异曲同工之处的。

    我们 (f_{ij}) 记录第 (j) 个元素,经过 (2^i) 次翻转后,这个元素的值。

    (f_{0,j})

    好,那么显然,我们要先求出 (f_{0,j})

    read(n);read(m);read(k);//读入
    for(int i=1;i<=m;i++)read(a[i]),read(b[i]);//读入
    for(int i=1;i<=n;i++)c[i]=i;//给c数组赋初值
    for(int i=1;i<=m;i++)reverse(c+a[i],c+b[i]+1);//模拟
    for(int i=1;i<=n;i++)f[0][i]=c[i];//经过1次翻转第i个元素的值为c[i]
    

    写倍增

    因为 (2^i=2^{i-1}+2^{i-1})

    所以,(f_{i,j}=f_{i-1,f_{i-1,j}})

    给第 (j) 个元素操作 (2^{i-1}) 次,再操作 (2^{i-1}) 次,就相当于直接操作 (2^i) 次。

    学过 (LCA) 的应该都会。

    for(int i=1;i<=30;i++)
    	for(int j=1;j<=n;j++)
    		f[i][j]=f[i-1][f[i-1][j]];//就是之前的公式
    

    得到答案

    我们知道,任何一个十进制整数都是可以转成二进制形式

    这里的话,我们就拆分 (k)。这里的步骤也很像 (LCA)

    for(int i=1;i<=n;i++){
    	int x=i,m=k;
    	for(int j=30;j>=0;j--)
    		if(m>=(1ll<<j)){
    			m-=(1ll<<j);//拆
    			x=f[j][x];//操作
    		}
    	writen(x);//输出
    }
    

    复杂度

    这个复杂度显然是 (O(n log k)) 是一个不错的复杂度。

    总代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    template<typename T>inline void read(T &FF){
    	T RR=1;FF=0;char CH=getchar();
    	for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
    	for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
    	FF*=RR;
    }
    template<typename T>inline void write(T x){
    	if(x<0)putchar('-'),x*=-1;
    	if(x>9)write(x/10);
    	putchar(x%10+48);
    }
    template<typename T>inline void writen(T x){
    	write(x);
    	puts("");
    }
    const int MAXM=1e2+10,MAXN=1e5+10;
    int n,m,k,a[MAXM],b[MAXM],c[MAXN],f[35][MAXN];
    int main(){
    	read(n);read(m);read(k);
    	for(int i=1;i<=m;i++)read(a[i]),read(b[i]);
    	for(int i=1;i<=n;i++)c[i]=i;
    	for(int i=1;i<=m;i++)reverse(c+a[i],c+b[i]+1);
    	for(int i=1;i<=n;i++)f[0][i]=c[i];
    	for(int i=1;i<=30;i++)
    		for(int j=1;j<=n;j++)
    			f[i][j]=f[i-1][f[i-1][j]];
    	for(int i=1;i<=n;i++){
    		int x=i,m=k;
    		for(int j=30;j>=0;j--)
    			if(m>=(1ll<<j)){
    				m-=(1ll<<j);
    				x=f[j][x];
    			}
    		writen(x);
    	}
    	return 0;
    }
    

    后记

    感谢 @LightningUZ 帮我调了这道题的代码,帮我调出了一个小错误。

    如果题解有误,欢迎在下面评论或私信我,使得这篇题解更好。

  • 相关阅读:
    尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行 已解决!
    iis 无法在Web服务器上启动调试。打开的URL的IIS辅助进程当前没有运行
    aspx页面,Page_Load 无人进入,解决
    Ajax后台传数组参数,接收不到报错!
    FusionCharts和highcharts 饼图区别!
    redis
    Hibernate不同数据库的连接及SQL方言
    Kafka
    Zookeeper
    BaseDao+万能方法 , HibernateDaoSupport
  • 原文地址:https://www.cnblogs.com/zhaohaikun/p/12593714.html
Copyright © 2011-2022 走看看