191109-T1~T2

T1 排兵布阵

题目描述

在游戏中有 n n n 座城堡,每局对战由两名玩家来争夺这些城堡。每名玩家有 m m m 名士兵,可以向第 i i i 座城堡派遣 a i a_i ai 名士兵去争夺这个城堡,使得总士兵数不超过 m m m 。如果一名玩家向第 i i i 座城堡派遣的士兵数严格大于对手派遣士兵数的 2 2 2 倍,那么这名玩家就占领了这座城堡,获得 i i i 分。

现在你即将和其他 s s s 名玩家两两对战,这 s s s 场对决的派遣士兵方案必须相同。小 F 通过某些途径得知了其他 s s s 名玩家即将使用的策略并告诉了你,你应该使用某种策略策略来最大化总分。

由于方案可能不唯一,你只需要输出你能获得的总分的最大值。

输入格式

输入第一行包含三个正整数 s , n , m s,n,m s,n,m ,分别表示除了小 X 以外的玩家人数、城堡数
和每名玩家拥有的士兵数。

接下来 s s s 行,每行 n n n 个非负整数,表示一名玩家的策略,其中第 i i i 个数 a i a_i ai 表示这
名玩家向第 i i i 座城堡派遣的士兵数。

输出格式

输出一行一个非负整数,表示你能获得的最大得分

输入样例

2 3 6
2 2 10
0 0 0

输出样例

8

一种最佳策略为向第 1 1 1 座城堡派遣 2 2 2 名士兵,向第 2 2 2 座城堡派遣 5 5 5 名士兵,向第 3 3 3 座城堡派遣 1 1 1 名士兵。

数据范围

对于 10 % 10\% 10% 的数据,保证 s = 1 , n ≤ 3 , m ≤ 10 s=1,n\le3,m\le10 s=1,n3,m10
对于 20 % 20\% 20% 的数据,保证 s = 1 , n ≤ 10 , m ≤ 100 s=1,n≤10,m\le100 s=1,n10,m100
对于 40% 的数据,保证 n ≤ 10 , m ≤ 100 n\le10,m\le100 n10,m100
对于另外 20 % 20\% 20% 的数据,保证 s = 1 s=1 s=1
对于 100 % 100\% 100% 的数据,保证
1 ≤ s ≤ 100 1\le s \le100 1s100 1 ≤ n ≤ 100 1\le n \le 100 1n100 1 ≤ m ≤ 2 ∗ 1 0 4 1\le m \le2*10^4 1m2104
对于每名玩家, a i ≥ 0 , ∑ i = 1 n a i ≤ m a_i\ge0,\sum_{i=1}^{n}a_i\le m ai0,i=1naim
注意常数问题

解析

显然,最优的策略是在一座城市不派遣士兵或刚好派可以拿下这个城的士兵 ( x < < 1 ∣ 1 x<<1|1 x<<11) 选一个。接下来就是背包问题的一点变化(背包容积:士兵总数;物品重量:选前 k k k 个所有即选到的最大的那一个;物品价值:点的编号 i ∗ k i*k ik(这一列击杀 k k k 人) )。DP方程见参考代码。时间复杂度 O ( n m s ) O(nms) O(nms) ,在全部取最大的时候可能会有点卡,所以合理地加 i n l i n e inline inline r e g i s t e r register register , 开启读入优化是必需的。常数减小,可以安全通过。

code

#include<bits/stdc++.h>
using namespace std;
int s,n,m;
int a[123][123],aa[123];
int dp[123][20002],ss[123],tt[123][123];
inline int Read(){
	int x=0;
	char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x;
}
inline void Write(int x){
	if(x>=10)Write(x/10);
	putchar(x%10+48);
}
int main(){
	s=Read(),n=Read(),m=Read();
	register int i,j,k;
	if(s==1){
		for(i=1;i<=n;++i)aa[i]=Read()<<1|1;
		for(i=1;i<=n;++i){
			for(j=1;j<=m;++j){
				if(j>=aa[i])dp[i][j]=max(dp[i-1][j],dp[i-1][j-aa[i]]+i);
				else dp[i][j]=dp[i-1][j];
			}
		}
	}
	else{
		for(i=1;i<=s;++i){
			for(j=1;j<=n;++j)a[i][j]=Read()<<1|1,tt[j][i]=a[i][j];
		}
		for(i=1;i<=n;++i)sort(tt[i]+1,tt[i]+s+1);
		for(i=1;i<=n;++i){
			for(j=1;j<=m;++j){
				for(k=1;k<=s;++k){
					if(j>=tt[i][k])dp[i][j]=max(dp[i][j],max(dp[i-1][j],dp[i-1][j-tt[i][k]]+i*k));
					else dp[i][j]=max(dp[i][j],dp[i-1][j]);
				}
			}
		}
	}
	Write(dp[n][m]);
	return 0;
}

祝贺自己成功地在考场上推出了比较复杂的状态转移方程,加油!\

T2 小X的二叉树

题目描述

小 X 研究的二叉树是一棵有 n n n 个点的 ∆ k ∆k k 树。
小 X 认为,没有点权的二叉树是没有灵魂的,于是这棵树第 i i i 个点有点权 a i a_i ai
小 X 认为,一棵二叉树是 ∆ k ∆k k 树,当且仅当任意一个点的点权和它的所有祖先的点权的差的绝对值都不超过 k k k。显然地,如果一棵二叉树是 ∆ k ∆k k 树,那么它一定是 ∆ ( k + 1 ) ∆(k+1) (k+1) 树。
小 X 认为,一棵 ∆ k ∆k k 树按照中序遍历构成的序列一定有优美的性质。

然而趁小 X 想着这个二叉树睡着的时候,小 R 把他的树删了。小 X 醒后发现自己的树不见了,还好中序遍历得到的点权序列 p p p 还在。小 X 想让你帮他检查一下,这个序列是否可以通过一棵 ∆ k ∆k k中序遍历得到。

输入格式

第一行一个整数 T T T ,表示数据组数。
每组数据包括:
第一行两个整数 n , k n,k n,k 。第二行共 n n n 个数,描述中序遍历的序列。

输出格式

T T T 行,分别是每组数据的询问结果, Y e s / N o Yes/No Yes/No 存在或不存在。

输入样例

3
6 10
2 7 15 8 9 5
6 8
2 7 15 8 9 5
6 7
2 7 15 8 9 5

输出样例

Yes
Yes
No

数据范围

对于 10 % 10\% 10% 的数据, 1 ≤ n ≤ 5 1\le n\le5 1n5
对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 200 1\le n\le 200 1n200
对于 60 % 60\% 60% 的数据, 1 ≤ n ≤ 5 ∗ 1 0 3 1\le n\le 5*10^3 1n5103
对于全部的数据, 1 ≤ n ≤ 2 ∗ 1 0 5 , 1 ≤ Σ n ≤ 1 0 6 , 0 ≤ p i , k ≤ 1 0 9 , 1 ≤ T ≤ 6 1\le n\le2*10^5,1\le\Sigma n\le10^6,0\le p_i,k\le10^9,1\le T\le6 1n2105,1Σn106,0pi,k109,1T6

解析

\

L v .   1 Lv.~1 Lv. 1

暴搜瞎搞, O ( u n k n o w n ) O(unknown) O(unknown) ,期望得分 10 \color{f02800}10 10

L v .   2 Lv.~2 Lv. 2

注意到题目中每个点对它祖先的限制,可以等价为一个点对它子树的限制,而中序遍历中每个子树是一个区间,所以可以区间 D P DP DP 。设 f ( l , r ) f(l,r) f(l,r) 表示区间 [ l , r ] [l,r] [l,r] 是否可行,转移时枚举当前区间表示子树的根 i i i ,需要满足 p i − k p_i−k pik 不超过区间 min ⁡ \min min p i + k p_i+k pi+k 不小于区间 max ⁡ \max max 。时间复杂度 O ( n 3 ) O(n^3) O(n3) ,期望得分: 30 \color{f08b00}30 30

L v .   3 Lv.~3 Lv. 3

注意到如下结论:题目中给定的序列合法的充要条件是对于任意一个区间,都存在一个数使得这个数与区间其他数的差的绝对值不超过 k k k 。感性理解就是寻找区间是否存在满足条件的数,如果存在,就不用继续从其他合法的点往下搜了。如果到了左右端点重合的时候,这部分返回 1 1 1 。如果当前的点左边和右边都合法就是合法,继续向下,否则不合法。如果啥没有搜到返回 0 0 0

详细说明:

充分性:
若任意一个区间都满足此性质,那么我们一定可以构造出一棵满足题意的二叉树。我们从区间 [ 1 , n ] [1,n] [1,n] 开始构造,选择一个满足条件的 i i i ,将 i i i 作为当前子树的根,接着递归构造 [ l , i − 1 ] [l,i−1] [l,i1] [ i + 1 , r ] [i+1,r] [i+1,r] 。由于每个区间都存在一个数满足条件,所以一定有合法的 i i i,也就能构造出满足题意的树。

必要性:
如果这是由一棵合法的树中序遍历得到的点权序列,那么每个区间中深度最浅(最先抓出)的点一定是其他点的祖先,而这个点必须要满足条件,所以每个区间一定存在一个数,满足与区间内其他数的差的绝对值不超过 k k k 。于是我们就要判断原序列是否每个区间都存在一个数满足与其他数的差的绝对值不超过 k k k 。我们考虑分治,对于当前区间 [ l , r ] [l,r] [l,r] ,找到一个 i ( l ≤ i ≤ r ) i(l\le i\le r) i(lir) 使得 p i − k p_i−k pik 不超过区间 min ⁡ \min min p i + k p_i+k pi+k 不小于区间 max ⁡ \max max ,这时跨过 i i i 的区间一定都合法,分治到 [ l , i − 1 ] [l,i−1] [l,i1] [ i + 1 , r ] [i+1,r] [i+1,r] 判断即可。

时间复杂度 T ( n ) = T ( k ) + T ( n − k − 1 ) + O ( k ) = O ( n 2 ) T(n)=T(k)+T(n−k−1)+O(k)=O(n^2) T(n)=T(k)+T(nk1)+O(k)=O(n2) ,期望得分: 60 \color{bef000}60 60

L v .   4 Lv.~4 Lv. 4

因为上一个级别是分开枚举的,因此时间复杂度次数是 2 2 2 。怎么优化呢?注意到位置不影响答案,可以改为同时从区间两端往中间扫,走一步同时判两个是否合法(第 t t t 步判断 l + t l+t l+t r − t r-t rt )。时间复杂度: T ( n ) = T ( k ) + T ( n − k − 1 ) + min ⁡ { O ( k ) , O ( n − k ) } = O ( n log ⁡ 2 n ) T(n)=T(k)+T(n−k−1)+\min\{O(k),O(n−k)\}=O(n\log_2n) T(n)=T(k)+T(nk1)+min{O(k),O(nk)}=O(nlog2n) 。对于区间最小值可以用 S T ST ST 表线性对数预处理,查询 O ( 1 ) O(1) O(1) 。总的时间复杂度是 O ( n log ⁡ 2 n ) O(n\log_2n) O(nlog2n) 。期望得分: 100 \color{00e600}100 100

code

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int n,k,stmax[233333][19],stmin[233333][19],a[233333];//在WOJ不能加inline或register小心RE 
int QD(int ll,int rr){//查小 
	int kk=log2(rr-ll+1);
	return max(stmax[ll][kk],stmax[rr-(1<<kk)+1][kk]);
}
int QX(int ll,int rr){//查大 
	int kk=log2(rr-ll+1);
	return min(stmin[ll][kk],stmin[rr-(1<<kk)+1][kk]);
}
int fhltql(int l,int r){
	if(l>=r)return 1;//到底了,不用拆分了 
	int minn=QX(l,r),maxx=QD(l,r);//求区间极大值极小值 
	for(int i=0;i+l<=r-i;i++){//两边向中枚举,不会在大区间耗时过多 
		if(a[l+i]-k<=minn&&a[l+i]+k>=maxx)//左指针满足deltaKtree 
		return fhltql(l,l+i-1)&&fhltql(l+i+1,r);//左边和右边依次递归,两边都可以才合法 
		if(a[r-i]-k<=minn&&a[r-i]+k>=maxx)//右指针满足deltaKtree
		return fhltql(l,r-i-1)&&fhltql(r-i+1,r);//小F太强了 
	}
	return 0;//啥都没有找到,宣告失败
}
int main(){
	int T;scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&k);
		int i,j;//卡常数
		for(i=1;i<=n;i++){
			scanf("%d",&a[i]);
			stmax[i][0]=stmin[i][0]=a[i];//底层
		}
		for(j=1;j<=18;j++){
			for(i=1;i+(1<<j)-1<=n;i++){
				stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<(j-1))][j-1]);//建大值斯特表 
				stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<(j-1))][j-1]);//建小值斯特表 
			}
		}
		if(fhltql(1,n))puts("Yes");//总区间存在 
		else puts("No");//不存在 
	}
	return 0;//完结撒花
}

预 祝 C S P 取 得 理 想 成 绩 ! \color{f0f000}预祝CSP取得理想成绩! CSP

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值