20210913测试

20210913测试

封面来源

Pixiv ❄❄❄-95028648

20210913测试

[toc]

1.排列

题目链接: 原题P4678

题目描述

定义两个数组 A, B 相似,当且仅当满足以下条件:

  1. A, B 的长度相等,设其为 $n$。
  2. 对于所有 $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 f[N][N*(N-1)/2],fac[N+10],invfac[N+10];
int fac[N],invfac[N],f[N][N*(N-1)/2];
//f[i][j]长度为i逆序对数为j的情况数
//可得f[i][j]=sum(f[i-1][k],k in range(1,j));
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(){//处理f[i][j]
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';
}
作者

Steve Li

发布于

2021-09-13

更新于

2022-01-22

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×