今日总结2024/5/8

今日熟悉了贪心的上升下降子序列长度的优化解法以及和dfs的结合

以及LCS朴素写法

Acwing 287.导弹防御系统

为了对抗附近恶意国家的威胁,R𝑅 国更新了他们的导弹防御系统。

一套防御系统的导弹拦截高度要么一直 严格单调 上升要么一直 严格单调 下降。

例如,一套系统先后拦截了高度为 33 和高度为 44 的两发导弹,那么接下来该系统就只能拦截高度大于 44 的导弹。

给定即将袭来的一系列导弹的高度,请你求出至少需要多少套防御系统,就可以将它们全部击落。

输入格式

输入包含多组测试用例。

对于每个测试用例,第一行包含整数 n𝑛,表示来袭导弹数量。

第二行包含 n𝑛 个不同的整数,表示每个导弹的高度。

当输入测试用例 n=0𝑛=0 时,表示输入终止,且该用例无需处理。

输出格式

对于每个测试用例,输出一个占据一行的整数,表示所需的防御系统数量。

数据范围

1≤n≤50

输入样例:

5
3 5 2 4 1
0 

输出样例:

2

思路: 

首先看到严格单调递增和严格单调下降就想到最长上升和下降子序列

本题可以选择上升子序列和下降子序列,但每次不知道选择哪一个,所以只能进行暴力搜索来穷举最优解,使用全局变量ans来记录最小方案并更新

对于上升子序列,使用贪心的方法,可以用一个单调数组来维护结尾的序列值以及子序列的长度,每次做的操作就是将该数加入到该单调数组中,但该单调数组并不是最终的最长上升子序列

只是长度与之相等,因此我们遍历这个序列每次将用这个数来更新单调数组,若在尾部加入则单调数组长度+1,若在内部加入则将该值替换单不改变单调性

对于最长上升子序列则是每次将加入的数放入结尾数最大的且小于加入的数那个,因为如果加入到结尾最小的那个后面就会导致不是最优解

对于最长下降子序列则是每次将加入的数放入结尾数最小的且大于加入数的那个

最后暴力枚举即可

#include <iostream>
#include <algorithm>
#define endl '\n'
using namespace std;
const int N=51;
int a[N],n,ans;
int up[N],down[N];//上升序列结尾数,下降序列结尾数

void dfs(int u,int s,int x){//当前枚举到第几个数,上升子序列个数,下降子序列个数
    if(s+x>=ans) return;
    if(u==n){
        ans=s+x;
        return;
    }
    //开始搜索上升子序列个数和下降子序列个数
    int k=0;
    while(k<s&&up[k]>=a[u]) k++;
    int t=up[k];//保存状态
    up[k]=a[u];//添加
    if(k<s) dfs(u+1,s,x);//如果新数被合并了
    else dfs(u+1,s+1,x);//如果新加了一个
    up[k]=t;//恢复
    
    k=0;
    while(k<x&&down[k]<=a[u]) k++;
    t=down[k];
    down[k]=a[u];
    if(k<x) dfs(u+1,s,x);
    else dfs(u+1,s,x+1);
    down[k]=t;
}

int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    while(cin>>n,n){
        for(int i=0;i<n;i++) cin>>a[i];//读入
        ans=n;
        dfs(0,0,0);
        cout<<ans<<endl;
    }
    return 0;
}
最长公共子序列朴素写法

f[i][j]为包含a前i个数,b前j个数的子序列长度,属性为最大值

f[i-1][j-1]包含于f[i-1][j]和f[i][j-1],所以取最值一般省略

选第i个不选第j个包含于f[i][j-1],另外一个同理,再和最后一个i,j都选f[i-1][j-1]+1取最值即可

由于第i,j个不一定相等要进行特判

#include <iostream>
using namespace std;
const int N=1e3+7;
int f[N][N],n;

int main(){
    cin>>n;
    string s1,s2;
    cin>>s1>>s2;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++){
        f[i][j]=max(f[i-1][j],f[i][j-1]);
        if(s1[i-1]==s2[j-1]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
    }
    cout<<f[n][n];
    return 0;
}

<think>好的,我现在要处理用户的问题,他们之前已经询问过如何编写SQL查询来获取今日之前的数据,现在他们调整了需求,想要包括今日今日之前的数据。我需要先回顾之前的对话,确保理解当前问题的上下文。 首先,用户之前的查询使用了`DATE(pp.create_time) < CURDATE()`来筛选今日之前的记录。现在他们希望包括今天的数据,所以条件需要改为小于等于今天。这时候应该把`< CURDATE()`改为`<= CURDATE()`,或者更简洁的方式是直接使用`< CURDATE() + INTERVAL 1 DAY`,这样可以避免函数转换,可能提升性能,特别是如果create_time是datetime类型的话。 接下来,我需要检查之前的回答是否提到了日期函数的转换,比如使用DATE()函数来提取日期部分。用户现在可能需要考虑create_time字段是否包含时间部分。如果字段是datetime类型,并且用户想包括今天的所有时间,比如从00:00:00到23:59:59,那么原来的条件可能需要调整。例如,`pp.create_time < CURDATE() + INTERVAL 1 DAY`会更准确,因为它涵盖了今天的所有时间,而不仅仅是午夜之前。 另外,在之前的优化建议中,我提到了使用INNER JOIN来确保只统计有公司信息的记录,以及改用COUNT(*)提高性能。用户现在可能需要同样的优化建议,尤其是在处理更大的数据集时,性能优化仍然重要。 用户可能没有明确说明的是,他们是否希望包括今天的数据,但可能没有意识到时间部分的处理。例如,如果他们使用`DATE(pp.create_time) <= CURDATE()`,这会正确包括今天的所有时间,因为DATE()函数会去掉时间部分,所以任何今天的时间都会被算作等于CURDATE()。但直接比较`pp.create_time < CURDATE() + INTERVAL 1 DAY`可能更高效,特别是当create_time有索引时,避免使用函数可以更好地利用索引。 此外,用户可能希望确保分组正确。在之前的回答中,我提到GROUP BY需要包括pc.company_name,以避免严格模式下的错误。这一点在修改后的查询中仍然适用,需要再次强调,确保用户不会遗漏。 还需要考虑潜在的问题,比如create_time字段的数据类型。如果是DATE类型,那么直接比较没有问题;如果是DATETIME或TIMESTAMP,则需要处理时间部分。用户可能没有意识到这点,需要明确指出,避免出现逻辑错误。 最后,用户可能需要知道如何测试这个查询,以确保它确实包括了今天的数据。可以建议他们插入一些测试数据,包括今天的日期,然后运行查询来验证结果是否符合预期。 总结来说,我需要将之前的条件从“今日之前”调整为“今日及之前”,并解释不同的实现方式及其优缺点,同时提醒用户注意时间部分的处理、分组字段的正确性以及性能优化的可能性。此外,提供测试建议也是帮助用户确认查询正确性的好方法。</think>```sql SELECT pp.company_id AS companyId, pc.company_name AS companyName, COUNT(pp.id_card_no) AS count FROM project_personnel pp LEFT JOIN project_company pc ON pp.company_id = pc.id WHERE pp.project_id = 'qj60f5928cc780fb42543cb3a5' AND pp.cur_state = 'IN' AND DATE(pp.create_time) <= CURDATE() -- 关键修改点 GROUP BY pp.company_id, pc.company_name ``` **修改说明与注意事项**: 1. **核心逻辑变化** 将原条件`DATE(pp.create_time) < CURDATE()`修改为`DATE(pp.create_time) <= CURDATE()`,包含今日数据(以服务器时区为准) 2. **时间判断详解** - `CURDATE()`:返回当前日期(格式:$YYYY-MM-DD$,不含时间部分) - `DATE(pp.create_time)`:提取datetime字段的日期部分 - 等价判断:$\text{创建日期} \leq \text{今日}$ 3. **潜在问题预警** - **时区问题**:若数据库时区与业务时区不一致,可能导致包含/排除错误日期 - **性能影响**:对`create_time`字段使用`DATE()`函数会破坏索引使用(可优化为`pp.create_time < CURDATE() + INTERVAL 1 DAY`) 4. **优化建议版本** ```sql SELECT pp.company_id AS companyId, pc.company_name AS companyName, COUNT(*) AS count FROM project_personnel pp INNER JOIN project_company pc -- 内连接确保数据完整性 ON pp.company_id = pc.id WHERE pp.project_id = 'qj60f5928cc780fb42543cb3a5' AND pp.cur_state = 'IN' AND pp.create_time < CURDATE() + INTERVAL 1 DAY -- 避免函数转换 GROUP BY pp.company_id, pc.company_name ``` **对比两种条件写法**: | 条件表达式 | 适用场景 | 索引使用 | 执行效率 | |---------------------------------|-----------------------------------|--------------------|----------| | `DATE(pp.create_time) <= CURDATE()` | 字段为datetime类型 | 无法使用索引 | 较低 | | `pp.create_time < CURDATE() + INTERVAL 1 DAY` | 字段为date/datetime类型 | 可以使用索引 | 较高 | **推荐验证方式**: ```sql -- 查看当前数据库时间 SELECT NOW(), CURDATE(), CURDATE() + INTERVAL 1 DAY; -- 测试数据样例(假设今天是2024-03-15) INSERT INTO project_personnel (id_card_no, create_time, cur_state, project_id, company_id) VALUES ('A123', '2024-03-15 08:00:00', 'IN', 'qj60f...', 1), -- 应被统计 ('A124', '2024-03-14 23:59:59', 'IN', 'qj60f...', 1), -- 应被统计 ('A125', '2024-03-16 00:00:01', 'IN', 'qj60f...', 1); -- 不应被统计 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值