封面来源
Pixiv ❄❄❄-95028648
20210913测试
[toc]
1.排列
题目链接: 原题P4678
题目描述
定义两个数组 A, B 相似,当且仅当满足以下条件:
- A, B 的长度相等,设其为 $n$。
- 对于所有 $i(1 ≤ i ≤ n)$,A 中小于 $A[i]$ 的元素个数等于 B 中小于 $B[i]$ 的元素个数。
对于两个排列 P1, P2,定义 F(P1, P2) 等于满足$ P1[l · · · r] $相似于 P2$[l · · · r](1 ≤ l ≤ r ≤ n)$,
并且 $P1[l · · · r]$ 中逆序对数量小于 E 的$ (l, r)$ 的合法对数 (即合法子区间数,$Pi
[l · · · r]$
表示由$ Pi
[l], Pi
[l + 1], · · · , Pi$
[r] 组成的数组。)
对$ P1, P2$ 取遍所有$ n$ 个元素的排列,求$ F(P1, P2)$ 的总和。
题意
求(任意两个长度为$N$的全排列的贡献)之和,而两个数列中位置相等的两段区间,且满足各区间内数字大小关系相等,逆 序对个数不大于$E$的区间贡献为$1$。
分析
设$f_{i,j}$表示长度为$i$,逆序对个数为$j$的方案数。于是可打表,得到如下的表格
$$ \begin{matrix} 1_{i=1,k=0}\1_{i=2,k=0}&1\1_{i=3,k=0}&2&2&1\1_{i=4,k=0}&3&5&6&5&3&1\1_{i=5,k=0}&4&9&15&20&22&20&15&9&4&1_{k=10} \end{matrix} $$
看前几行会觉得可能是$f_{i,j}=f_{i-1,j}+f_{i,j-1}$,但是$20+3 \not=22 $。所以只能DP了。
发现因为新插入的$i$严格大于$1\to i-1$,所以插入$i$带来的新逆序对个数为$0\to i-1$。所以有$f_{i,j}=\sum_{k=j-i+1}^jf_{i-1,k}$。
然后用对每次询问,枚举区间长度,用组合式计算区间放不同数字和区间在不同位置的方案数,输出即可。
最后放一个通式$$ans = \sum_{i=1}^{i \leq n} [ ( C_n^i A_{n-i}^{n-i} )^2 \times cnt_{i,k} C_{n-i+1}^{1} ] = \sum_{i=1}^{i \leq n} [ (\frac{n!}{i!} )^2cnt_{i,k} C_{n-i+1}^{1} ]$$。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| #include<bits/stdc++.h> #define FOR(i,l,r) for(register int i=l;i<=r;++i) #define ROF(i,l,r) for(register int i=l;i>=r;--i) using namespace std; #define int long long const int N = 505; const int mo = 1e9+7;
int fac[N],invfac[N],f[N][N*(N-1)/2];
int T,n,E,PreLong,Long; const int M = (N-1)*N/2; inline int min(int a,int b){ return a>b?b:a; } inline int mod(int &a){ if(a>=mo)a%=mo; return a; } int Qpow(int x,int y){ int ans = 1;mod(x); while(y){ if(y&1)mod(ans*=x); mod(x*=x),y>>=1; } return ans; } inline int PreWork(){ int N = 500,M = (N-1)*N/2; fac[0]=1; FOR(i,1,N)fac[i]=fac[i-1]*i%mo; invfac[N]=Qpow(fac[N],mo-2); ROF(i,N-1,0)mod(invfac[i]=invfac[i+1]*(i+1)%mo); FOR(i,0,M)f[1][i]=1; FOR(i,2,N){ f[i][0]=1;Long=(i-1)*i/2; FOR(j,1,Long){ mod(f[i][j]=f[i][j-1]+f[i-1][min(j,PreLong)]); if(j>=i)mod(f[i][j]=f[i][j]-f[i-1][min(j-i,PreLong)]+mo); } PreLong=Long; } return 0; } inline int C(int n,int m){ return fac[n]%mo*invfac[m]%mo*invfac[n-m]%mo; } inline int PF(int x){ return x*x%mo; } signed main(){ PreWork(); cin>>T; while(T--){ cin>>n>>E;int ans = 0; E = min(n*(n-1)/2,E); FOR(i,1,n)mod(ans+=f[i][min(E,i*(i-1)/2)]*(n-i+1)%mo*PF(C(n,i)%mo*fac[n-i]%mo)%mo); cout<<ans%mo<<endl; } }
|
2.六边形
据说是一个状压DP,不会,这里放上标程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include <bits/stdc++.h> using namespace std; const int mod=1e9+7; inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);} inline void up(int &x,int y) {x=add(x,y);}
int A[34],B[34],top,L,k,bin[34]; int low,upi,ans=0; int f[34][113][(1<<5)+10][2],vis[34][113][(1<<5)+10][2],vs; int tr[(1<<5)+10][(1<<5)+10],ok[(1<<5)+10]; inline void init() { for(int i=0;i<(1<<5);i++) { static int len[5]; for(int z=0;z<=4;z++) len[z]=((i>>z)&1) ? 1 : (z?len[z-1]+1:1); for(int z=0;z<=4;z++) if(len[z]>k) ok[i]=1; for(int j=0;j<(1<<5);j++) { static int anc[5],val[5]; for(int z=0;z<=4;z++) anc[z]=((i>>z)&1) ? z : (z-1); for(int z=0;z<=4;z++) val[z]=((j>>z)&1) ? 1 : 0; for(int z=1;z<=4;z++) if(!val[z] && anc[z]!=z && (z?val[z-1]:0)) {tr[i][j]=-1; break;} if(~tr[i][j]) { for(int z=0;z<=4;z++) if(anc[z]==z || (val[z] && !(z?val[z-1]:0))) tr[i][j]|=(1<<z); } } } } inline int dfs(int pos,int res,int sta,bool lim) { if(res>=10) return 0; if(res<-101) res=-101; if(!pos) { if(res>=0 || !(sta&1)) return 0; return ok[sta] ? 0 : min(upi-low+1,-res); } int kth=res+101; int &s=f[pos][kth][sta][lim]; if(vis[pos][kth][sta][lim]==vs) return s; s=0; for(int i=0;i<bin[5];i++) if(~tr[sta][i]) { if(lim && ((i>>4)&1) && !B[pos]) continue; up(s,dfs(pos-1,res*2+A[pos]-__builtin_popcount(i),tr[sta][i],lim&&((i>>4)&1)==B[pos])); } return vis[pos][kth][sta][lim]=vs, s; } inline int solve(int n) { top=0; ++vs; while(n) A[++top]=n&1, n>>=1; for(int i=0;i<=max(top+1,5);i++) bin[i]=1<<i; return dfs(top,0,0,1); } int main() { freopen("hexagons.in", "r", stdin); freopen("hexagons.out", "w", stdout); cin>>upi>>low>>L>>k; while(L) B[++top]=L&1, L>>=1; init(); cout<<solve(low)<<'\n'; }
|