首页 > 其他分享 >[题解] permutation

[题解] permutation

时间:2024-08-22 19:14:55浏览次数:11  
标签:ch int 题解 sum cdots split permutation binom

[题解] Permutation

image

image

image

解析

一眼 DP 或者 组合。

70pts

场上推的DP

对于 \((4,2,2)\),先把所有序列枚举出来:

\[\begin{split} 1\ \ \ 2\\ 1\ \ \ 3\\ 1\ \ \ 4\\ --\\ 2\ \ \ 3\\ 2\ \ \ 4\\ 3\ \ \ 4 \end{split} \]

可以发现,对于分割线上的部分,可以看作 \((3,1,1)\) 的所有序列每个数 \(+1\),然后前导一个 \(1\)。因为答案计算的是绝对值,所以每个数加一相当于整体抬高,不影响答案。而对于分割线下的部分,可以看作 \((3,2,2)\) 的所有序列每个数 \(+1\),同样不影响答案。令 \(f(i,j,z)\) 表示对应 \((n,k,m)\) 的答案。那么有:

\[f(i,j,z)=f(i-1,j-1,z-1)+f(i-1,j,z)+? \]

留个问号是因为,这两部分合并还可以产生贡献,为上面部分最后一个数与下面部分第一个数的差的绝对值。上面部分最后一个数为 \(i\),下面部分第一个数为 \(j+1\)。所以有:

\[\begin{split} f(i,j,z)&=f(i-1,j-1,z-1)+f(i-1,j,z)+|i-j-1|\\ \end{split} \]

\[\begin{split} f(i,i,z)&=0\\ f(i,j,1)&=i-j \end{split} \]

但 \(i,j,z\) 都是 \(10^6\) 级别的,空间会炸。可以发现 \(i\) 只和 \(i-1\) 有关,可以滚掉。\(j\) 和 \(z\) 同减,并且 \(z\le j\),那么只维护最小的 \(z\) 即可。

场码
#include<bits/stdc++.h>
using namespace std;
constexpr int B = 1 << 23;
char buf[B], *p1 = buf, *p2 = buf;
#define gt() (p1==p2 && (p2=(p1=buf)+fread(buf, 1, B, stdin), p1==p2) ? EOF : *p1++)
template <typename T> inline void rd(T &x){
	x = 0; int f = 0; char ch = gt();
	for(; !isdigit(ch); ch = gt()) f ^= ch == '-';
	for(; isdigit(ch); ch = gt()) x = (x<<1) + (x<<3) + (ch^48);
	x = f ? -x : x;
}
char obuf[B], *O = obuf;
#define pt(ch) (O-obuf==B && (fwrite(obuf, 1, B, stdout), O=obuf), *O++=(ch))
template <typename T> inline void wt(T x){
	if(x < 0) pt('-'), x = -x;
	if(x >= 10) wt(x / 10); pt(x % 10 ^ 48);
}
#define fw fwrite(obuf, 1, O - obuf, stdout)
#define ll long long
#define ull unsigned long long
constexpr int N = 1e6 + 5, M = 1e9 + 7;
int n, k, m, f[2][N], lst, now = 1;
int main(){
//	freopen("perm.in", "r", stdin);
//	freopen("perm.out", "w", stdout);
	rd(n), rd(k), rd(m);
	if(n == k) wt(m);
	else {
		int tmp = k - m;
		for(int i=tmp; i<=n; ++i){
			for(int j=max(1, m+i-n); j+tmp<=i; ++j){
				if(j == 1) f[now][j] = i - (j + tmp);
				else if(i == j + tmp) f[now][j] = 0;
				else f[now][j] = ((ll)f[lst][j] + (ll)f[lst][j-1] + abs(i - j - tmp - 1)) % M;
			}
			for(int j=max(i, m+i-1-n); j+tmp<=i-1; ++j) f[lst][j] = 0;
			now ^= 1, lst ^= 1;
		} wt(f[lst][m]);
	} return fw, 0;
}

另一种 DP 思路

先打表找规律。打出 \(8\) 以内的表可以发现,答案只和 \(n-m\) 和 \(k\) 相关,那么把 \(k\) 设为横坐标,\(n-m\) 设为纵坐标,于是有:

\[\begin{matrix} 1&2&3&4&5&\cdots\\ 1&4&9&16&25&\cdots\\ 1&6&17&36&65&\cdots\\ 1&8&27&66&135&\cdots\\ 1&10&39&108&247&\cdots\\ 1&12&53&164&415&\cdots\\ \vdots&\vdots&\vdots&\vdots&\vdots&\ddots \end{matrix} \]

令 \(f(i,j)\) 表示图上对应横坐标与纵坐标的值。于是有:

\[f(i,j)=f(i-1,j)+f(i,j-1)+j \]

注意边界判断:

\[\begin{split} f(1,i)=i+1\\ f(i,0)=0 \end{split} \]

答案即为:

\[f(k,n-m-1) \]

于是 \(\mathcal{O}(n^2)\) 递推即可。

100pts

考虑优化刚才的那个 DP,可以发现,对于点 \((i,j)\) 的答案可以看作是从这个点一直走到到点 \((0,0)\) 的所有路径的权值总和。这个东西可以用组合求解。可以枚举每一个点 \((i,j)\),一共有 \(\binom{i+j}{i}\) 条路径经过这一点。对于边界 \(i=1\) 需要特判一下,看作权值为 \(1\)。于是可以列出式子:

\[\sum_{i=0}^{m-2}\sum_{j=0}^{n}(n-j)\binom{i+j}{j}+\sum_{j=0}^{n}\binom{m-1+j}{j} \]

但是这个式子是 \(\mathcal{O}(n^2)\) 的。所以考虑优化。有一个公式:

\[\sum_{i=m}^{n}\binom{a+i}{i}=\binom{a+n+1}{n}-\binom{a+m}{m-1} \]

用上面的式子套公式即可优化到一维:

\[\sum_{j=0}^{n}\binom{j+m-2}{j+1}+\sum_{j=0}^{n}\binom{m-1+j}{j} \]

复杂度 \(\mathcal{O}(n)\)。

code
#include<bits/stdc++.h>
using namespace std;
constexpr int N = 1e6 + 5, M = 1e9 + 7;
int n, m, k, ans, p[N<<1], inv[N<<1];
#define ll long long
inline int qpow(int a, int k){
	int as = 1;
	while(k){
		if(k & 1) as = (ll)as * a % M;
		a = (ll)a * a % M; k >>= 1;
	} return as;
}
inline int C(int a, int b){
	return (ll)p[a] * inv[b] % M * inv[a-b] % M;
}
int main(){
	freopen("perm.in", "r", stdin);
	freopen("perm.out", "w", stdout);
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin>>n>>m>>k;
	if(n == m) return cout<<m, 0;
	n -= m + 1;
	p[0] = 1; for(int i=1; i<=n+m; ++i) p[i] = (ll)p[i-1] * i % M;
	inv[n+m] = qpow(p[n+m], M-2); for(int i=n+m-1; i>=0; --i) inv[i] = (ll)inv[i+1] * (i+1) % M;
	if(k >= 2) for(int j=0; j<=n; ++j) ans = ((ll)ans + (ll)(n-j) * C(j+k-1, j+1) % M) % M;
	for(int j=0; j<=n; ++j) ans = ((ll)ans + (ll)C(k+j-1, j)) % M;
	return cout<<ans, 0;
}

标签:ch,int,题解,sum,cdots,split,permutation,binom
From: https://www.cnblogs.com/xiaolemc/p/18374557

相关文章

  • csp模拟27-金箱子(题解)
    题目链接(显然还没有找到原题)虽说我现在才学会期望dp显得不太好,但没办法,谁让我比较菜~~,之前模拟赛已经考过几道类似的题了,但都一笔带过了,这次算是正式学习了一下这类题,于是就有了这篇题解。首先看到k次方首先想到的就是我们在进行dp转移的时候不太方便,这个时候很自然的想到二项......
  • 题解:P9041 [PA2021] Fiolki 2
    \(\text{Link}\)题意给定一个\(n\)个点\(m\)条边的DAG,定义\(f(l,r)\)表示最多选取多少条不相交路径\((s_i,t_i)\)满足\(s_i\in[1,k],t_i\in[l,r]\),其中不能有任意一点同时在两条选出的路径上。对\(\forallx\in[0,k)\)求出有多少\([l,r]\sube(k,n]\)使得\(f(l,r)......
  • 题解:P10881「KDOI-07」能量场
    \(\text{Link}\)题意给你一个长为\(n\)的序列\(a_{1\dotsn}\),定义一条边\((u,v)\)的权值为\(a_u+a_v\)。对于一张图,定义其权值为包含的所有边的权值乘积。求所有\(n\)个点的有标号基环树的权值之和。对\(998244353\)取模。\(n\le10^3\)。思路非常厉害的题,zky倾......
  • 题解:P10698 [SNCPC2024] 最大流
    \(\text{Link}\)题意给定一个\(n\)个点\(m\)条边的单位网络,保证该网络不存在环。给定一个常数\(k\),设从\(1\)到\(i\)的最大流为\(f_i\),对\(\foralli\in[2,n]\)求出\(\min(f_i,k)\)。\(n\le10^5\),\(m\le2\times10^5\),\(k\le\min(n-1,50)\)。思路不相交路径,考......
  • 升级Openssh 后 最大文件打开数修改不生效,启动 UsePAM yes后 ,最大文件打开数生效但是
    感谢 博主https://blog.csdn.net/Daphnisz/article/details/124040904vi /etc/pam.d/sshd(注意不是/etc/pam.d/sshd.pam)#%PAM-1.0auth required pam_sepermit.soauthsubstackpassword-authauthincludepostlogin#Usedwithpolkittoreauthor......
  • 常见问题解决 --- 为什么我们常常发现服务器没有管理的端口
    我们在扫描一台主机全端口,发现没有开放管理端口,比如windows远程桌面或者是linux的ssh登陆。我列举一下常见的原因。常规管理方式:1.管理口不是常见的3389和22端口,而改为了高位端口号,避免被人发现。2.在管理端口上加上了安全策略导致无法直接连接,比如私钥登陆方......
  • 题解:CF1986B Matrix Stabilization
    洛谷传送门题意一个\(n\timesm\)的矩阵,依次进行以下操作:从\((1,1)\)开始遍历矩阵,找到最小的\((i,j)\)满足\(a{i,j}\)的值严格大于其所有相邻(四联通)单元格的值,如果没有则退出将1操作找到的\(a_{i,j}-1\)返回1操作求最后的矩阵。思路模拟,我们按照题目所说,从......
  • 题解:P7020 [NWRRC2017] Boolean Satisfiability
    题目传送门题目大意给定一个由大小写字母(变量),|和~组成的布尔代数式,变量可以任意赋值为True或False。求对于给定的变量,有多少种赋值方案使得给定的代数式值为True。思路一个一个看,首先考虑|,先假设只有|,则当代数式中有一个变量为True时,代数式的值变为True。因为每一......
  • 题解:P9788 [ROIR 2020 Day2] 区域规划
    题目传送门思路首先我们看下数据范围,$n<=3000$,范围很小,所以暴力枚举。于是第一份代码出来了。#include<bits/stdc++.h>usingnamespacestd;ints,a,b,c,d,n,m;intmain(){ ios::sync_with_stdio(false); cin.tie(),cout.tie(); cin>>n>>m; for(a=1;a<=n;a++) {......
  • 题解:P9784 [ROIR 2020 Day1] 超速
    传送门思路我们设\(T\)为所花的总时间,\(d\)为超速多少。然后不难知道$T=\sum_{i=1}^{n}\frac{l_i}{v_i+d}$,所以我们实际上是要找到符合条件最小的\(d\)。再结合题目所说最高被罚款的金额最少,然后二分枚举答案即可。时间复杂度\(O(nq\log(m))\)。AC代码#include......