Featured image of post 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';
}
所念皆星河
Built with Hugo
主题 StackJimmy 设计