首页 > 其他分享 >[20241024] T3 题解

[20241024] T3 题解

时间:2024-10-20 21:14:07浏览次数:1  
标签:10 int 题解 个数 T3 序列 20241024 dp mod

细节挺多的。

题意

有一个长度为 \(n\) 的数组 \(a\) 和一个长度为 \(m\) 的队列 \(q\),初始时 \(q\) 中的元素和为 \(0\)。对 \(x=1,2,\cdots,n\) 进行如下操作:

  • 如果队首元素 \(q_1<a_x\),则 \(q\) 弹出队首,将 \(a_x\) 插入队尾。

在操作结束后,定义数组 \(a\) 的 权值 为 \(q\) 中元素的和。

给定长度为 \(n\) 的数字 \(b\),\(b\) 中元素两两不等。求数组 \(b\) 重拍后得到的所有排列 \(a\) 的权值值和,对 \(10^9+7\) 取模。

\(n,m \le 500\)。

思路

image

首先,我们定义数组 \(p\) 表示加入过队列 \(q\) 的元素。上述例子中 \(p=[1,9,2,6,3,10,4]\),其个数 \(n_p\) 定义为 \(a\) 的

假定 \(p\) 的元素个数为 \(n_p\),则对于 \(i \le n_p-m\),满足 \(p_i<p_{i+m}\)。考虑将 \(v \notin p\) 中的元素插入到 \(p\) 中,使其变成数组 \(a\),插入的条件为对于 \(m+1 \le i \le n_p+1\),\(i\) 与 \(i-1\) 之间插入的数字序列 \(S_i\) 中的每个元素 \(\le p_{i-m}\),可以发现,\(i\) 后面插入的数字与 \(p_{i-m}\) 有关,而 \(p_i\) 也只是与 \(p_{i-m}\) 有关,所以我们考虑对每个 \(0 \le j < m\),\(i \bmod m=j\) 组成的子序列进行计数。

整理一下,对于每个子序列 \([p_{i_1},p_{i_2},\cdots,p_{i_l}]\),满足 \(p_{i_j}<p_{i_{j+1}}\),而 \(S_{i_j}\) 中的元素 \(\le\) \(p_{i_j-1}\)。

对这种序列 \(dp\),考虑令 \(f_{i,j}\) 表示填了 \(i\) 个数字,其度为 \(j\) 个的方案数个数。对于每个 \(i\) 考虑从大到小求解,令 \(g_{j,k}\) 表示放了最大的 \(j\) 个数字,其度为 \(k\) 的方案数个数。转移枚举第 \(j-1\) 大的数字在不在 \(p\) 序列即可。

考虑对原序列进行计数,令 \(\lfloor \frac{n_p}{m} \rfloor=x\),则原序列的 \(p\) 序列的每个子序列长度为 \(x\) 或 \(x+1\),子序列个数总和为 \(m\)。而对于位置 \(n_p\) 与 \(n_p+1\) 之间填的数字,考虑可以在统计 \(p\) 序列后强行添加 \(n+1\) 进行计算。而因为枚举 \(x\) 的时候保证不重复,对于统计 \(x\) 的时候,保证至少有一个子序列长度 \(x\)。显然,\((n_p+1) \bmod m\) 子序列原本只有 \(x\) 个,加入 \(n+1\) 后会是 \(x+1\) 个元素,称这种子序列为特殊子序列。

令 \(dp_{1,i,j}\) 表示 \(p\) 序列中填了 \(j\) 个长度为 \(x\) 的子序列,\(a\) 序列中填了 \(i\) 个的方案数。

令 \(dp_{2,i,j}\) 表示 \(p\) 序列中填了 \(j\) 个长度为 \(x + 1\) 的子序列,\(a\) 序列中填了 \(i\) 个的方案数。

令 \(dp_{0,i,j}\) 表示 \(p\) 序列中填了 \(m-1\) 个子序列,包含特殊子序列,\(x+1\) 子序列的个数为 \(j\) 个,\(a\) 序列中填了 \(i\) 个的方案数。

令 \(dp_{3,i,j}\) 表示 \(p\) 序列中填了 \(m-1\) 个子序列,刚好不包含特殊子序列,\(x+1\) 子序列的个数为 \(j\) 个,\(a\) 序列中填了 \(i\) 个的方案数。

然后考虑统计答案,即每个 \(p\) 序列最后 \(m\) 个元素的权值和(不包含 \(n+1\)),枚举一下即可,需要分情况讨论,用到 \(dp_{0,i,j}\) 与 \(dp_{3,i,j}\)。

因为 \(j \le m\),而且 \(x \le \frac nm\),复杂度是 \(O(n^3)\)。

#include <bits/stdc++.h>
using namespace std;

#define vi vector<int>
#define pb push_back
#define pii pair<int,int>
#define mkp make_pair

int rd() {
	int x = 0, f = 1;
	char ch = getchar();
	while (!('0' <= ch && ch <= '9')) {
		if (ch == '-') f = -1; ch = getchar();
	}
	while ('0' <= ch && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();
	}
	return x * f;
}

void wr(int x) {
	if (x < 0) putchar('-'), x = -x;
	if (x >= 10) wr(x / 10); putchar(x % 10 + '0');
}
bool MemoryST;

const int N = 510;
const int mod = 1e9 + 7;

int b[N];
int c[N][N], p[N];
int dp1[N][N], dp2[N][N], dp3[N][N];

int n, m, dp[N][N], f[N][N], g[N][N];

void init(int n) {
	for (int i = 0; i <= n; ++i) {
		c[i][0] = c[i][i] = 1;
		for (int j = 1; j < i; ++j)
			c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
	}
}

void Add (int &x, int y) {
	x += y;
	if (x >= mod) x -= mod;
}

int ksm (int x, int y = mod - 2) {
	int res = 1;
	while (y) {
		if (y & 1) res = 1ll * res * x % mod;
		x = 1ll * x * x % mod; y >>= 1;
	}
	return res;
}

void Mainsolve() {
	int n, m; cin >> n >> m;
	init(n + 1);
	for (int i = 1; i <= n; ++i)
		cin >> b[i];
	for (int i = 1; i <= n; ++i)
		for (int x = i; x <= n; ++x)
			p[i] = (p[i] + 1ll * c[x - 1][i - 1] * b[x] % mod) % mod;
	for (int i = 1; i <= n + 1; ++i) {
		for (int j = 1; j <= i; ++j)
			for (int k = 1; k <= i; ++k)
				g[j][k] = 0;
		g[i][1] = 1;
		for (int j = i; j >= 2; --j)
			for (int k = 1; k <= i; ++k)
				Add(g[j - 1][k + 1], g[j][k]), Add(g[j - 1][k], 1ll * g[j][k] * (i - j) % mod);
		for (int j = 1; j <= i; ++j)
			f[i][j] = g[1][j];
	}
	int ans = 0; 
	int inv = ksm(m - 1);
	for (int x = 1; x <= n / m; ++x) {
		for (int i = 0; i <= n + 1; ++i)
			for (int j = 0; j <= m; ++j)
				dp1[i][j] = dp2[i][j] = dp3[i][j] = dp[i][j] = 0;
		dp1[0][0] = 1;
		for (int i = 0; i < n + 1; ++i)
			for (int j = 0; j < m; ++j)
				for (int k = 1; k <= n + 1 - i; ++k)
					Add(dp1[i + k][j + 1], 1ll * dp1[i][j] * f[k][x] % mod * c[i + k][i] % mod);
		// dp1[i][j] 表示 i 个点,有 j 个位置的方案数个数,填的个数是 x 
		dp2[0][0] = 1;
		for (int i = 0; i < n + 1; ++i) 
			for (int j = 0; j < m; ++j)
				for (int k = 1; k <= n + 1 - i; ++k)
					Add(dp2[i + k][j + 1], 1ll * dp2[i][j] * f[k][x + 1] % mod * c[i + k][i] % mod);
		// dp2[i][j] 表示 i 个点,有 j 个位的方案数个数,填的数字是 x + 1 
		for (int i = 0; i <= n + 1; ++i)
			for (int j = 0; j <= n + 1 - i; ++j)
				for (int k = 0; k <= m - 1; ++k) 
					Add(dp3[i + j][k], 1ll * dp1[i][m - 1 - k] * dp2[j][k] % mod * c[i + j][i] % mod);
		for (int i = n + 1; i >= 0; --i)
			for (int j = 0; j < m; dp2[i][j] = 0, ++j)
				for (int k = 1; k <= n + 1 - i; ++k)
					Add(dp2[i + k][j + 1], 1ll * dp2[i][j] * f[k][x + 1] % mod * c[i + k - 1][i] % mod);
		for (int i = 0; i <= n + 1; ++i)
			for (int j = 0; j <= n + 1 - i; ++j)
				for (int k = 0; k <= m - 1; ++k)
					Add(dp[i + j][k], 1ll * dp1[i][m - 1 - k] * dp2[j][k] % mod * c[i + j - 1][i] % mod); 
		// dp[i][j] 表示 i 个点,有 j 个位置填了 x + 1 的数字的方案数
		for (int i = 1; i <= n; ++i) {
			for (int j = 0; j <= m - 1; ++j)
				Add(ans, 1ll * f[i + 1][x + 1] * dp3[n - i][j] % mod * p[i] % mod);
			for (int j = 1; j <= m - 1; ++j)
				Add(ans, 1ll * f[i][x] * dp[n + 1 - i][j] % mod * (m - j) % mod * p[i] % mod);
			for (int j = 1; j <= m - 1; ++j) 
				Add(ans, 1ll * f[i][x + 1] * dp[n + 1 - i][j] % mod * j % mod * p[i] % mod);
		}
	}
	cout << ans << endl;
}

bool MemoryED;
int main() {
//	freopen ("potential.in", "r", stdin);
//	freopen ("potential.out", "w", stdout);
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	cerr << fixed << setprecision(6) << (&MemoryST - &MemoryED) / 1048576.0 << "MB\n";

	int T = 1;
	while (T--) Mainsolve();

	cerr << endl << 1e3 * clock() / CLOCKS_PER_SEC << "ms\n";
	return 0;
}

标签:10,int,题解,个数,T3,序列,20241024,dp,mod
From: https://www.cnblogs.com/wangzhongyuan/p/18487890

相关文章

  • springboot3.0自动配置
    目标本文主要介绍springboot3.0是如何创建一个可以进行自动配置的jar包的自动配置的定义是,一个jar包里面定义了一些spring的bean,当导入这个jar包的时候会自动将这些bean导入进去方法创建AutoConfiguration.imports文件创建目录META-INF/spring/org.springframework.boot.a......
  • 2024 ICPC Asia Taiwan Online Programming Contest题解记录
    比赛链接:https://codeforces.com/gym/105383/problemA.AnimalFarm找个最大pig,然后所有比他小的其他种类生物一直加就好了#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constllmod=1e9+7;llksm(llx,lly){ llans=1; while(y) { if(y&1)......
  • P10233 [yLCPC2024] A. dx 分计算 题解
    题目大意:题目传送门共\(T\)组测试数据,每组数据给定一个字符串\(s\)和\(Q\)次询问,按照特定的赋值方式,每次询问\(l\)到\(r\)间按这样的赋值方式的总和是多少。赋值方式如下:P可得3分p可得2分G可得1分其余字符不得分题目分析:前置知识:前缀和。(没有学过的可以先......
  • 题解:AT_abc376_c [ABC376C] Prepare Another Box
    很好的一道二分答案题。听说CSP考前写tj可以让rp+=inf?注:下文中\(w\)指物品重量序列,\(x\)指箱子容量序列。先问个问题:为什么我上来就敢肯定这是个二分答案题?或者说,单调性在哪儿?非常简单:如果一个盒子的容量越大,能装下的东西就更多(废话)。那么如果\(v\)不够用,可以扩......
  • 【学校训练记录】10月个人训练赛4个人题解
    A:要使s,t相等只要互相删除对方没有的字母即可,即找到a-z字母拥有最少的#include<bits/stdc++.h>#defineendl"\n"#defineintlonglongusingnamespacestd;strings1,s2;inta1[30],a2[30];voidsolve(){ cin>>s1>>s2; for(inti=0;i<s1.size(......
  • 【洛谷 P1116】车厢重组 题解(模拟+冒泡排序)
    车厢重组题目描述在一个旧式的火车站旁边有一座桥,其桥面可以绕河中心的桥墩水平旋转。一个车站的职工发现桥的长度最多能容纳两节车厢,如果将桥旋转度,则可以把相邻两节车厢的位置交换,用这种方法可以重新排列车厢的顺序。于是他就负责用这座桥将进站的车厢按车厢号从小到大排列。他......
  • 【洛谷 P1116】车厢重组 题解(模拟+冒泡排序)
    车厢重组题目描述在一个旧式的火车站旁边有一座桥,其桥面可以绕河中心的桥墩水平旋转。一个车站的职工发现桥的长度最多能容纳两节车厢,如果将桥旋转度,则可以把相邻两节车厢的位置交换,用这种方法可以重新排列车厢的顺序。于是他就负责用这座桥将进站的车厢按车厢号从小到大排列。他......
  • CF1187E 题解
    Titletranslation给定一棵\(n\)个点的树,初始全是白点。要做\(n\)步操作,每一次选定一个与一个黑点相隔一条边的白点,将它染成黑点,然后获得该白点被染色前所在的白色联通块大小的权值。第一次操作可以任意选点,求可获得的最大权值。Solution如何让这道题秒降绿题呢?先简化一......
  • 题解:AT_abc376_c [ABC376C] Prepare Another Box
    这道题要求把\(a\)数组和\(b\)数组一一匹配,且要求无法匹配的数量最多为一,并且这个无法匹配的元素最小。可以注意到我们把两个数组排序以后一一对应以后如果出现一个无法匹配的元素,那么这一定就是答案。但是如果我们从小到大枚举,会发现最后剩下的元素不一定最小,所以我们选择......
  • 【题解】「COCI 2018」Teoretičar
    LinkofThisProblem根据Vizing定理,最小的答案就是二分图的最大度数。同时可以在\(O(nm)\)的时间复杂度内构造出一组解。显然对于这道题我们需要更高效的做法。注意到\(2\)的整数次幂,考虑分治。既然答案跟最大度数有关,如果我们每次能把边集分为两个集合,认为她们的颜色......