zoukankan      html  css  js  c++  java
  • P3322 [SDOI2015]排序 暴搜

    题意:

    戳这里

    分析:

    通过手玩样例 , 我们可以发现以下几条性质:

    1. 一个合法的操作序列,各个操作其实是互不影响的,也就是说,只要我们发现了一组合法的操作序列,那么它的全排列是都可以的
    2. 对于一种排列,有且仅有一种合法的操作集合,因为任意一类操作是无法通过别的其他操作等价替换的

    那么我们将问题转化成了枚举操作集合,判断是否可行

    然后我们发现从小到大进行每个操作,进行第 (i) 种操作后,情况合法当且仅当每 (2^{i-1}) 个数都是单调递增的

    对于样例而言:

    进行第一次操作后的合法情况应该是 :(7,8,5 ,6,1,2,3,4)

    对于第 (i) 种操作,分情况讨论:

    1. 若没有需要操作的区间,跳过
    2. 若有一个需要操作的区间,直接修改
    3. 若有两个操作的区间,分 4 种情况进行修改
    4. 若有两个以上的区间不合法,则无解

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
    	inline long long read()
    	{
    		long long x=0,f=1;char ch=getchar();
    		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    		return x*f;
    	}
    	
    	const int maxn = 4100;
    	long long n,ans;
    	long long a[maxn],pw[maxn],fac[maxn];
    	
    	bool check(int x,int l)
    	{
    		for(int i=1;i<l;i++) 
    		if(a[x+i]!=a[x+i-1]+1) return false;
    		return true;
    	}
    	
    	void swap(int x,int y,int l)
    	{
    		for(int i=0;i<l;i++) std::swap(a[x+i],a[y+i]);
    	}
    	
    	void dfs(int k,int num)
    	{
    		if(k>n)
    		{
    			ans+=fac[num];
    			return ;
    		}
    		int tmp1=0,tmp2=0;
    		for(int i=1;i<=pw[n];i+=pw[k])
    		{
    			if(!check(i,pw[k]))
    			{
    				if(!tmp1) tmp1=i;
    				else if(!tmp2) tmp2=i;
    				else return ;
    			}
    		}
    		if(!tmp1&&!tmp2) dfs(k+1,num);
    		else if(tmp1&&!tmp2)
    		{
    			swap(tmp1,tmp1+pw[k-1],pw[k-1]);
    			dfs(k+1,num+1);
    			swap(tmp1,tmp1+pw[k-1],pw[k-1]);
    		}
    		else
    		{
    			for(int x=0;x<=1;x++)
    			{
    				for(int y=0;y<=1;y++)
    				{
    					swap(tmp1+x*pw[k-1],tmp2+y*pw[k-1],pw[k-1]);
    					if(check(tmp1,pw[k])&&check(tmp2,pw[k])) dfs(k+1,num+1);
    					swap(tmp1+x*pw[k-1],tmp2+y*pw[k-1],pw[k-1]);
    				}
    			}
    		}
    	}
    	
    	void work()
    	{
    		n=read();
    		fac[0]=pw[0]=1;
    		for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i,pw[i]=pw[i-1]*2;
    		for(int i=1;i<=pw[n];i++) a[i]=read();
    		dfs(1,0);
    		printf("%lld
    ",ans);
    	}
    
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    关于神奇的MD5算法21
    【转】C# 轻松实现对窗体(Form)换肤
    个人代码库のXML操作演练
    个人代码库の自定义后缀名
    个人代码库の自定义不规则窗体和控件
    个人代码库の创建快捷方式
    jquery 实现省市级联动
    分析器错误消息: 无法识别的属性“targetFramework”。请注意属性名称区分大小写
    EXTJS 面板控件panel应用
    HTTP 错误 500.21 Internal Server Error处理程序
  • 原文地址:https://www.cnblogs.com/youth518/p/13958532.html
Copyright © 2011-2022 走看看