Uest 1421 Adjacent Bit Counts dp

本文介绍了一个使用动态规划解决特定计数问题的方法。通过定义dp[i][j][?]来表示状态,其中i为位数,j为根据规律求出的和,?表示当前位的值。状态转移方程考虑了相邻位之间的关系,实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[110][110][2];

void getsolve(){
	memset(dp,0,sizeof(dp));
	dp[1][1][1]=0;
	dp[1][0][1]=1;
	dp[1][0][0]=1;
	dp[1][1][0]=0;
	for(int i=2;i<=100;i++){
		for(int j=0;j<=100;j++){
			dp[i][j][0]=dp[i-1][j][1]+dp[i-1][j][0];
			if(j>=0)
			dp[i][j][1]=dp[i-1][j-1][1]+dp[i-1][j][0];
		}
	}

}

int main()
{
	getsolve();
	int t,n,m;
	scanf("%d",&t);
	while(t--){
		int c;
		scanf("%d%d%d",&c,&n,&m);
		printf("%d %d\n",c,dp[n][m][0]+dp[n][m][1]);
	}
	return 0;
}
分析:dp[i][j][?]表示总共有i位,j表示根据规律求出的和为j,其中?=0表示i这个值为0,?=1表示i这个值为1;
      又根据计算原则:有两个相邻的1则值为1,所以可得如下状态转移方程
      状态转移方程:dp[i][j][0]=dp[i-1][j][1]+dp[i-1][j][0];
                      dp[i][j][1]=dp[i-1][j-1][1]+dp[i-1][j][0];
<think>好的,我现在需要解决用户的问题,即如何从表t_main中删除相邻的重复项,并通过lifnr字段进行比较。首先,我需要理解用户的需求。用户提到了“删除相邻重复项”,这可能意味着他们希望删除表中连续出现的重复记录,而不仅仅是所有重复项。同时,他们希望根据lifnr字段进行比较,判断是否为重复项。 接下来,我需要回忆SQL中是否有直接处理相邻重复项的语句。通常,DELETE语句可以结合子查询或窗口函数来识别重复项。例如,使用ROW_NUMBER()窗口函数来为每一行分配序号,然后删除序号大于1的行。但这种方法通常用于删除所有重复项,而不仅仅是相邻的。不过,用户特别提到“相邻”,可能需要确保重复项是连续出现的。 另一个思路是使用自连接,比较当前行与前一行的lifnr值。如果当前行的lifnr与前一行相同,则标记为重复。但SQL中如何引用前一行呢?这时候可能需要使用LAG()窗口函数。LAG()可以访问前一行的数据,这样就能判断当前行是否与前一行在lifnr字段上重复。 接下来,我需要考虑如何实现这一点。例如,首先为表中的每一行生成一个行号,然后使用LAG(lifnr) OVER (ORDER BY 行号)来获取前一行的lifnr值。然后,在DELETE语句中,删除那些当前行的lifnr等于前一行的情况。但需要注意的是,SQL的DELETE语句中不能直接引用窗口函数的结果,因此可能需要使用CTE(公共表表达式)或子查询来临时存储这些信息。 此外,表是否有主键或唯一标识符也很重要,因为删除操作需要明确指定哪些行要删除。如果表没有主键,可能需要创建一个临时表或使用其他方法来确定要删除的行。 还需要注意,不同的数据库系统(如MySQL、SQL Server、PostgreSQL)可能有不同的语法支持。例如,MySQL 8.0以上支持窗口函数,而旧版本可能不支持。用户没有指定使用的数据库类型,但根据问题中的示例,可能假设是支持标准SQL的数据库。 总结步骤可能如下: 1. 确定表中的排序方式,因为“相邻”依赖于行的顺序。可能需要一个排序列,如时间戳或自增ID。 2. 使用窗口函数(如LAG)来比较当前行和前一行的lifnr值。 3. 标记需要删除的重复行,即当前行与前一行的lifnr相同。 4. 执行DELETE操作,删除这些标记的行。 但需要注意,如果没有明确的排序列,相邻的概念可能无法准确定义。因此,用户可能需要提供一个排序列,比如使用自增ID或时间戳来确保行的顺序。 例如,假设表t_main有一个自增主键id,可以按id排序,然后使用以下步骤: - 使用CTE为每一行获取前一行的lifnr值。 - 删除那些当前行的lifnr等于前一行且id较大的行(假设保留第一个出现的记录)。 可能的SQL语句如下: WITH cte AS ( SELECT id, lifnr, LAG(lifnr) OVER (ORDER BY id) AS prev_lifnr FROM t_main ) DELETE FROM t_main WHERE id IN ( SELECT id FROM cte WHERE lifnr = prev_lifnr ); 但需要验证这个逻辑是否正确,是否仅删除相邻的重复项。例如,如果有连续三个重复的lifnr,第一次删除中间的那个,但可能需要多次执行,或者使用更复杂的逻辑一次性处理。 此外,用户可能需要保留第一个或最后一个出现的记录。上述例子中,假设按id升序排列,保留第一个记录,删除后续相邻的重复项。如果是这种情况,那么上述方法有效。 但用户的问题中未明确说明如何处理多个相邻重复项,比如三个连续的相同lifnr。可能需要进一步确认需求,但根据一般情况,假设需要删除所有后续相邻重复项,仅保留第一个。 最后,确保语法正确,并考虑性能问题,尤其是当表数据量大时,使用窗口函数可能会影响性能。此外,如果表没有合适的排序列,可能需要先添加一个排序列或使用现有字段来定义顺序。</think>### 从表 `t_main` 删除相邻重复项的方法 #### 1. 理解“相邻重复项”的定义 在SQL中,“相邻”需要依赖明确的排序规则(例如按自增主键、时间戳排序)。若未指定顺序,需先添加排序列(如`id`)或使用现有字段定义逻辑顺序。 #### 2. 使用窗口函数标记重复项 通过`LAG()`函数比较当前行与前一行`lifnr`的值: ```sql WITH cte AS ( SELECT id, lifnr, LAG(lifnr) OVER (ORDER BY id) AS prev_lifnr -- 按主键id排序,获取前一行lifnr FROM t_main ) DELETE FROM t_main WHERE id IN ( SELECT id FROM cte WHERE lifnr = prev_lifnr -- 仅删除相邻重复项 ); ``` 此操作会删除与前一行的`lifnr`相同且`id`较大的记录,保留第一个出现的值[^1]。 #### 3. 处理无主键表的情况 若表无主键,需临时生成行号作为排序依据: ```sql WITH cte AS ( SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS row_num, -- 生成临时行号 lifnr FROM t_main ), marked AS ( SELECT row_num, lifnr, LAG(lifnr) OVER (ORDER BY row_num) AS prev_lifnr FROM cte ) DELETE FROM t_main WHERE EXISTS ( SELECT 1 FROM marked WHERE marked.row_num = t_main.row_num -- 假设已添加临时行号字段 AND marked.lifnr = marked.prev_lifnr ); ``` #### 4. 性能优化建议 - 在`lifnr`字段上创建非聚集索引以加速比较[^2]。 - 使用事务确保删除操作的原子性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值