CF2066D2 Club of Young Aircraft Builders (hard version)题解

请先读一下这篇文章

书接上文,我们只需要稍微动下小手术即可。

我们考虑对于 d p i , j , k dp_{i,j,k} dpi,j,k,依旧枚举 p p p(定义与上文一致),我们要求小于等于 j j j 的时间中,有恰好 c c c 个大于等于 i i i 的飞机,而 p + 1 , j p+1,j p+1,j 又全是大于等于 i i i 的,且 1 , j 1,j 1,j 中有一些已经确定的位置大于等于 i i i,我们记这个值为 q q q(可以容易前缀和预处理),则 1 , p 1,p 1,p 中一定恰有 c − q − j + p + p p c-q-j+p+pp c−q−j+p+pp 个,其中 p p pp pp 为 1 , p 1,p 1,p 中大于等于 i i i 的数量。

在 p p p 的变化过程中, p p pp pp 也在变化,所以我们需要对前缀和做下小手术。

如果我们这一次用 d p i − 1 , p , k k dp_{i-1,p,kk} dpi−1,p,kk 转移:

  • 若 a p ≥ i a_p\ge i ap≥i,下一次就一定用 d p i − 1 , p − 1 , k k dp_{i-1,p-1,kk} dpi−1,p−1,kk。
  • 否则下一次一定用 d p i − 1 , p − 1 , k k − 1 dp_{i-1,p-1,kk-1} dpi−1,p−1,kk−1。

另外,在 d p i , j , k dp_{i,j,k} dpi,j,k 中,如果 j j j 时刻后面有第 i i i 层发出的飞机(可以预处理),根据题意,需要将这个状态特判为 0 0 0。

依旧优雅~

::::success代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int t,n,c,m,a[10005];
int dp[10005][105],dpp[10005][105],s[10005][105];
int ksm(int x,int y)
{
	if(y==1) return x;
	if(!y) return 1;
	int mid=ksm(x,y>>1);
	if(y&1) return mid*1ll*mid%mod*x%mod;
	return mid*1ll*mid%mod;
}
int jie[10005],njie[10005];
int C(int x,int y)
{
	if(x<y) return 0;
	return jie[x]*1ll*njie[y]%mod*njie[x-y]%mod;
}
int q[10005][105],h[10005][105];
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0); 
	jie[0]=1,njie[0]=1;
	for(int i=1;i<=10000;i++) jie[i]=jie[i-1]*1ll*i%mod,njie[i]=ksm(jie[i],mod-2);
	cin>>t;
	while(t--)
	{
		cin>>n>>c>>m;
		for(int i=1;i<=m;i++) cin>>a[i];
		for(int i=1;i<=m;i++)
		{
			for(int j=1;j<=n;j++)
				if(j<=a[i]) q[i][j]=(q[i-1][j]+1)%mod;
				else q[i][j]=q[i-1][j];
		}
		for(int i=1;i<=n;i++) h[m+1][i]=0;
		for(int i=m;i>=1;i--)
		{
			for(int j=1;j<=n;j++)
				if(j==a[i]) h[i][j]=(h[i+1][j]+1)%mod;
				else h[i][j]=h[i+1][j];
		}
		for(int i=0;i<=c-q[c][1];i++) 
		{
			if(h[c+1][1]) continue ;
			dp[c][i]=C(c-q[c][1],i);
		}
		for(int j=1;j<=m;j++)
			for(int k=0;k<=c;k++) 
				if(a[j]) s[j][k]=(dp[j][k]+s[j-1][k])%mod;
				else s[j][k]=(dp[j][k]+s[j-1][k-1])%mod;
		for(int i=2;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				if(h[j+1][i]) continue ;
				for(int k=0;k<=c-q[j][i];k++)
				{
					if(c-(j-j)-q[j][i]>=0)
					dpp[j][k]=s[j][c-(j-j)-q[j][i]]*1ll*C(c-q[j][i],k)%mod;
				} 
			}
			for(int j=1;j<=m;j++)
				for(int k=0;k<=c;k++) dp[j][k]=dpp[j][k],dpp[j][k]=0;
			for(int j=1;j<=m;j++)
				for(int k=0;k<=c;k++) 
					if(a[j]) s[j][k]=(dp[j][k]+s[j-1][k])%mod;
					else s[j][k]=(dp[j][k]+s[j-1][k-1])%mod;
		}
		cout<<dp[m][0]<<"\n";
		for(int j=1;j<=m;j++)
			for(int k=0;k<=c;k++) dp[j][k]=0;
	}
	return 0;
}

::::

相关推荐
2401_868534783 小时前
RTOS之RT-Thread & Linux:线程/进程管理与调度核心差异分析
c++·python
wabs6664 小时前
关于图论【卡码网117.软件构建的思考】
数据结构·算法·软件构建·图论·卡码网
mifengxing4 小时前
LeetCode 41.缺失的第一个正数|Hard题O(n)+O(1)最优解法深度解析
java·算法·leetcode·排序算法
郝学胜-神的一滴5 小时前
Qt 高级编程 040:按钮悬浮弹出滑块弹窗的完整攻略
开发语言·c++·qt·软件工程·用户界面
Tongzhi20265 小时前
从部署到运维:通芝科技无感考勤一体机的全流程效率解析
运维·数据结构·科技·算法·贪心算法
Wang's Blog5 小时前
AI Agent白手起家30: 动态示例选择器之根据长度选择 Few Shot 示例
算法
oyguyteggytrrwwwrt7 小时前
自制交叉线路识别算法
算法
手写码匠7 小时前
华为云Flexus+DeepSeek征文|Dify 多智能体协同编排实战:R1 规划 + V3 执行,构建企业 Agent 团队
人工智能·深度学习·算法·aigc
晓天衡宇•评测社区8 小时前
FSR-Bench 前沿科学推理榜单发布:GPT-5.5 居首,“会推理”未必“能答对”
算法
程序喵大人9 小时前
【C++进阶】STL算法与函数对象 - 02 sort为什么需要随机访问迭代器
开发语言·c++·算法