zoukankan      html  css  js  c++  java
  • SRM517-600加强版(DP)

    题面

    给定一个{0, 1, 2, 3, ... , n - 1}的排列 p。一个{0, 1, 2 , ... , n - 2}的排列 q 被认为是优美
    的排列,当且仅当 q 满足下列条件:
    对排列 s = {0, 1, 2, 3, ..., n - 1}进行 n – 1 次交换。

    1. 交换 s[q0],s[q0 + 1]
    2. 交换 s[q1],s[q1 + 1]
      ...
      最后能使得排列 s = p.
      问有多少个优美的排列,答案对 10^9+7 取模。

    Solution

    考虑每一个i与p[i]是什么关系,就是说如果i<p[i],那么就是要向右交换。
    然后对于两个点之间的交换一定是唯一的,也就是只经过一次。
    所以就可以把每一个交换的方向(Theta(O(n^2)))的解决然后DP就好了。
    注意前缀和优化Dp

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #define ll long long
    #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    using namespace std;
    inline int gi(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    inline ll gl(){
    	ll sum=0,f=1;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    int o[10010];
    ll f[5010][5010],g[5010][5010],ans;
    vector<int>p;
    const int Mod=1e9+7;
    int main(){
    	file("swap");
        int i,j,k,n,m;
    	n=gi();
    	for(i=0;i<n;i++){
    		int x=gi();
    		p.push_back(x);
    	}
    	n=p.size();
    	memset(o,-1,sizeof(o));
    	for(i=0;i<n;i++)
    		if(i<p[i]){
    			if(i-1>=0){
    				if(!o[i-1])return puts("0"),0;
    				o[i-1]=1;
    			}
    			for(j=i;j<p[i]-1;j++)
    				if(o[j]==1)return puts("0"),0;
    				else o[j]=0;
    			if(p[i]-1<=n-3){
    				if(!o[p[i]-1])return puts("0"),0;
    				o[p[i]-1]=1;
    			}
    		}
    		else if(i>p[i]){
    			if(p[i]-1>=0){
    				if(o[p[i]-1]==1)return puts("0"),0;
    				o[p[i]-1]=0;
    			}
    			for(j=p[i];j<i-1;j++)
    				if(!o[j])return puts("0"),0;
    				else o[j]=1;
    			if(i-1<=n-3){
    				if(o[i-1]==1)return puts("0"),0;
    				o[i-1]=0;
    			}	
    		}
    		else return puts("0"),0;
    	f[0][1]=g[0][1]=1;
    	for(i=1;i<n-1;i++)
    		for(j=1;j<=i+1;j++){
    			if(o[i-1]!=1)
    				(f[i][j]+=g[i-1][j-1])%=Mod;
    			if(o[i-1]!=0)
    				(f[i][j]+=g[i-1][i]-g[i-1][j-1])%=Mod;
    			g[i][j]=(g[i][j-1]+f[i][j])%Mod;
    		}
    	for(i=1;i<n;i++)
    		(ans+=f[n-2][i])%=Mod;
    	ans%=Mod;
    	while(ans<0)ans+=Mod;
    	printf("%lld
    ",ans%Mod);
    	return 0;
    }
    
  • 相关阅读:
    高位前缀和,求他的子集的和https://ac.nowcoder.com/acm/contest/4784/A
    Codeforces Global Round 7 E. Bombs
    高精度,乘法加法
    2018-ICPC-焦作区预赛
    状压dp,区间dp,矩阵快速幂
    树状数组,适用于单点修改,区间查询
    离散化函数
    带修莫队模版
    树链剖分 https://www.luogu.com.cn/problem/P3384
    HDU 1016 Prime Ring Problem【DFS】
  • 原文地址:https://www.cnblogs.com/cjgjh/p/9798940.html
Copyright © 2011-2022 走看看