HUD 6044 Limited Permutation
来源:互联网 发布:网络掉包测试软件 编辑:程序博客网 时间:2024/05/17 08:37
HDU 6044 Limited Permutation
原题连接
http://acm.hdu.edu.cn/showproblem.php?pid=6044
在开始之前。提供一种加速读取的方法。
由于题目输入规模很大。所以建议使用下面代码来读入
利用fread() 批量读入内存。(下文中代码实现就是使用这个读入)
struct Io{ const char l='0'-1; const char r='9'+1; char A[MAXN]; char *ptop,*pend; Io() { ptop=pend=A; } void Io_fread() { pend=A+fread(A,1,MAXN,stdin); ptop=A; } bool read(int &a)//返回false表示什么也没读到 { if(ptop==pend)Io_fread(); if(ptop==pend)return false; while(*ptop==' '||*ptop=='\n'||*ptop=='\r'||*ptop=='\t') { ptop++; if(ptop==pend) { Io_fread(); if(ptop==pend)return false; } } a=0; while(*ptop>l&&*ptop<r&&ptop<pend) { a=a*10+(*(ptop++)-'0'); if(ptop==pend) Io_fread(); } return true; }}I;
开始正题。读题有可能忽略掉一个很重要的条件:
当且仅当 li≤L≤i≤R≤ri 时。
min(PL,PL+1,...PR)=Pi
当且仅当。意味着L,R 不满足上面条件时。
min(PL,PL+1,...PR)≠Pi
其实。如果没有忽略这样一个重要的条件。题目还是很有想头的。
那么对于上文条件。我们R 取ri+1 时。
min(PL,PL+1,...Pri+1)≠Pi
又:
min(PL,PL+1,...Pri)=Pi
则:min(PL,PL+1,...Pri+1)=Pri+1
这意味着:[li,ri]∈[lri+1,ri]
但是单纯从上面的方法出发对题目理解不够全面。
换个角度。
题目用。当且仅当这个词。那意味着。我们随意指定一个[L,R]
有且仅有一个i 满足:i∈[L,R],[L,R]∈[li,ri]
题目开始变的简单。为什么?
既然任意指定L,R 都应找到一个i
那么意味着:
必然存在覆盖[1,n] 的i
那么对于这样的一个i
也必然有覆盖:[1,i−1] , [i+1,n] 的限制区间。
似乎DFS , BFS 都可以解决。
因为我们得到了一个子问题:
我们记子区间[L,R] 对应的答案为:slove(L,R)
因为任意指定[L,R] 都有且仅有一个i 满足:i∈[L,R],[L,R]∈[li,ri]
所以如果存在 [lt,rt] 有:i∈[lt,rt] , [lt,rt]∈[li,ri]
则: slove(li,ri)=0
如果不存在某lt=li,rt=i−1
则 slove(li,ri)=0
因为开始的时候。answer=slove(1,n)
因为[1,n] 是全集。所以不存在不属于[1,n] 的区间。与[1,n] 有交。
归纳总结有:如果answer>0 .则不存在这样的i,j 有:
li≤lj≤ri≤rj
首先:
令lu=1,ru=n , slove(1,n)>0 .由之前的结论有:
不存在这样的i 有:li≤u≤ri
那么对于任意i 。有:[li,ri]∈[1,u−1] 或者[li,ri]∈[u+1,n]
那么对于任意t∈[1,u−1] 都有: [lt,rt]∈[1,u−1]
任意t∈[u+1,n] 都有:[lt,rt]∈[u+1,n]
其次:
记:lp=1,rp=u−1 或者lp=u+1,rp=n
slove(lp,rp)>0 ,则不存在这样的t 有:p∈[lt,rt] , [lt,rt]∈[lp,rp]
因为任意t∈[1,u−1] 都有: [lt,rt]∈[1,u−1]
因为任意t∈[u+1,n] 都有:[lt,rt]∈[u+1,n]
则slove(lp,rp) 是原问题的一个子问题。
当前区间。除了p 以外 , 在这个区间内的元素对应的区间要么属于[lp,p−1] 或者属于[p+1,rp]
那么有:
slove(li,ri)=slove(li,i−1)slove(i+1,ri)(ri−lii−li)
解释:计算完左右子树后。位置i 必须是最小值。但左右子树互不影响。
其中。两个slove() 是左右两边排列方案数。
(ri−lii−li) 是左右两边分配方案数。应用乘法乘法原理得到上式。
我们可以建立一棵区间包含关系的树。
根节点为区间[1,n]
root 的左孩子[1,u−1]
root 的右孩子[u+1,n]
其他节点依次类推。直到节点对应一个值
如果对于数组l[],r[] 可以成功建立上述区间包含关系的树。那意味着答案有解。
如果不能建立或者建立的树不合法。则answer=0
我们可以对区间排序。来建立这棵区间包含关系的树。
建议使用桶排序。由于输入时间较长。系统自带sort 不确定是否可过。
当然。也可以不建立树。直接DFS (但排序不可少)
也可以使用单调栈。
下面是
#include <stdio.h>#include <string.h>#include <algorithm>#define MAXN 1000006using namespace std;typedef long long LL;const int P=1e9+7;struct Io{ const char l='0'-1; const char r='9'+1; char A[MAXN]; char *ptop,*pend; Io() { ptop=pend=A; } void Io_fread() { pend=A+fread(A,1,MAXN,stdin); ptop=A; } bool read(int &a) { if(ptop==pend)Io_fread(); if(ptop==pend)return false; while(*ptop==' '||*ptop=='\n'||*ptop=='\r'||*ptop=='\t') { ptop++; if(ptop==pend) { Io_fread(); if(ptop==pend)return false; } } a=0; while(*ptop>l&&*ptop<r&&ptop<pend) { a=a*10+(*(ptop++)-'0'); if(ptop==pend) Io_fread(); } return true; }}I;int tmp[MAXN];void Sort(int *A,int *B,int *ton,int *Rank,int size)//桶排序。先比较A属性。后比较B属性。{ for(int i=0;i<size;i++) ton[i]=0; for(int i=1;i<size;i++) ton[B[i]]++; for(int i=1;i<size;i++) ton[i]+=ton[i-1]; for(int i=size-1;i;i--) tmp[ton[B[i]]--]=i;//对B属性排序 for(int i=0;i<size;i++) ton[i]=0; for(int i=1;i<size;i++) ton[A[i]]++; for(int i=1;i<size;i++) ton[i]+=ton[i-1]; for(int i=size-1;i;i--) Rank[ton[A[tmp[i]]]--]=tmp[i];}int L[MAXN];int R[MAXN];int chL[MAXN];int chR[MAXN];int fact[MAXN]={1,1};int Ifact[MAXN]={1,1};int ton[MAXN];int Rank[MAXN];int Q[MAXN];int ans[MAXN];int slove(int);int main (){ for(int i=2;i<MAXN;i++) Ifact[i]=P-(int)((LL)(P/i)*Ifact[P%i]%P); for(int i=1;i<MAXN;i++) { Ifact[i]=(LL)Ifact[i-1]*Ifact[i]%P; fact[i]=(LL)fact[i-1]*i%P; } int n,c=1; while(I.read(n)) { int size=n+1; for(int i=1;i<size;i++) I.read(L[i]); for(int i=1;i<size;i++) I.read(R[i]); Sort(L,R,ton,Rank,size); for(int i=1;i<size;i++) { if(L[Rank[i]]==L[Rank[i-1]]) chL[Rank[i]]=Rank[i-1]; else chL[Rank[i]]=0; } Sort(R,L,ton,Rank,size); for(int i=n-1; i ;i--) { if(R[Rank[i]]==R[Rank[i+1]]) chR[Rank[i]]=Rank[i+1]; else chR[Rank[i]]=0; } chR[Rank[n]]=0; printf("Case #%d: %d\n",c++,slove(size)); } return 0;}int slove(int size){ int rt=0,n=size-1; for(int i=1;i<size;i++) if(L[i]==1&&R[i]==n) { rt=i; break; } if(!rt)return 0; int l=0,r=1; Q[0]=rt; while(l<r) { int v=Q[l++]; if(chL[v]>0) { if(R[chL[v]]!=v-1)return 0; Q[r++]=chL[v]; } else if(L[v]!=v) return 0; if(chR[v]>0) { if(L[chR[v]]!=v+1 )return 0; Q[r++]=chR[v]; } else if(R[v]!=v)return 0; } while(r--) { int v=Q[r]; int cl=chL[v]; int cr=chR[v]; if(cl==0||cr==0) { ans[v]=ans[cl]+ans[cr]; if(ans[v]<1)ans[v]=1; continue; } int n=R[v]-L[v]; ans[v]=(LL)ans[cl]*ans[cr]%P; ans[v]=(LL)ans[v]*fact[n]%P*Ifact[v-L[v]]%P*Ifact[R[v]-v]%P; } return ans[rt];}
阅读全文
1 0
- HUD 6044 Limited Permutation
- hdu 6044 Limited Permutation
- HDU 6044 Limited Permutation 想法
- HDU-6044 Limited Permutation(计数)
- HDU 6044 Limited Permutation dfs 统计
- HDU 6044 Limited Permutation(递归)
- Limited Permutation HDU
- HDU 6044 Limited Permutation dfs + 组合数(读入挂)
- 2017 多校训练第一场 HDU 6044 Limited Permutation
- HDU 6044 Limited Permutation (组合数+逆元)
- 2017多校第一场 HDU 6044 Limited Permutation 思维,计数,DFS
- 2017多校联合第一场 1012题 hdu 6044 Limited Permutation 笛卡尔树 递归
- HDU6044 Limited Permutation[快速输入][分治]
- hdu6044 Limited Permutation【读入优化+dfs】
- 2017多校训练赛第一场 HDU 6044 Limited Permutation(虚建笛卡尔树+超级读入挂)
- Permutation HUD-3811 (状态压缩)
- HDU6044 Limited Permutation (递归,预处理阶乘逆元)
- HDU6044-Limited Permutation(fread挂&&阶乘求逆元&&组合数)
- HBase shell 命令创建表及添加数据操作
- @RequestParam @RequestBody @PathVariable 等参数绑定注解详解
- Spring DATA JPA[转载]
- 图解linx RAID的实现
- qt5中文乱码
- HUD 6044 Limited Permutation
- MUI预加载,从列表页到详情页
- 利用OpenCV进行图像配准
- js操作dom元素的例子
- requests库入门-3-urllib和requests小程序
- 算法提高 ADV-82 填充蛋糕
- Spark平台上的JavaWordCount示例
- 洛谷 P1796 汤姆斯的天堂梦_NOI导刊2010提高(05)
- [Python][小知识] Python字符串前 加 u、r、b 的含义