蓝桥31天|今天5道题Day6|C++

1.巧排扑克牌

在这里插入图片描述

直接手推

#include <iostream>
using namespace std;
int main(){
  //注意正面朝下
  cout<<"7, A, Q, 2, 8, 3, J, 4, 9, 5, K, 6, 10";
  return 0;
}

2.质数拆分

在这里插入图片描述
注意审题!是若干个两两不同,不是两个
即找出2~2019中和为2019的n个数一共有几种组合(非排列)
类似于01背包

#include <iostream>
using namespace std;
const int N=2500;
bool st[N];
int prime[N],cnt=1;
long long dp[N][N];
void isprime(){
  for(int i=2;i<=2019;i++){
     if(!st[i])prime[cnt++]=i;
     for(int j=1;prime[j]<=2019/i&&j<cnt;j++){
       
          
       st[i*prime[j]]=true;
       //这里注意j从1开始  %0会报错
       if(i%prime[j]==0)break;
     }
  }
}
int main()
{
  //从i个数中,使总和为j(2019)
  isprime();
  dp[0][0]=1;
  //涉及到[j-1],所以j从1开始
  for (int i = 1; i < cnt; i ++)
        for (int j = 0; j <= 2019; j ++)
        {
            dp[i][j] = dp[i - 1][j];                                  
            if(j >= prime[i]) dp[i][j] += dp[i - 1][j - prime[i]];     
        }
    

  printf("%lld",dp[cnt-1][2019]);
  return 0;
}

优化为一维

#include <iostream>
using namespace std;
const int N=2040;
int prime[N],cnt=0;
bool st[N];
long long dp[N];
void isprime(){
  //两个循环的等号必须加上
   for(int i=2;i<=N;i++){
     if(!st[i])prime[++cnt]=i;
     for(int j=1;prime[j]<=N/i;j++){
       st[prime[j]*i]=true;
       if(i%prime[j]==0)break;
     }
   }
}
int main(){
  //dp[i][j] 在前i个中选使得和为j
  isprime();

  dp[0]=1;
  for(int i=1;i<=cnt;i++){
     for(int j=2019;j>=0;j--){
       if(j>=prime[i])dp[j]+=dp[j-prime[i]];
     }
  }
  printf("%lld",dp[2019]);
  return 0;
}

3.日志统计

在这里插入图片描述

#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5+10;
struct Node{
  int ts,id;
  bool operator <(const Node& N)const{
    return ts<N.ts;
  }
}node[N];
int haash[N];
bool st[N];
int main()
{
  int n,d,k;
  scanf("%d%d%d",&n,&d,&k);
  for(int i=0;i<n;i++){
    scanf("%d%d",&node[i].ts,&node[i].id);
  }
  sort(node,node+n);
  for(int l=0,r=0;r<n;r++){
    haash[node[r].id]++;
    while(node[r].ts-node[l].ts>=d){
      haash[node[l].id]--;
      l++;
    }
    if(haash[node[r].id]>=k)st[node[r].id]=true;
  }
  for(int i=0;i<N;i++){
    if(st[i])printf("%d\n",i);
  }
  return 0;
}

4.递增三元组

在这里插入图片描述
Ai<Bi<Ci
根据N,判断时间复杂度大概为O(n)或O(nlogn)
循环B,找到小于B[i]的A有几个,大于B的C有几个
法一:前缀和 O(n)
cnt[i]表示A中i出现的次数
s[i]=cnt[0]~cnt[i] 表示0~i在A中的出现次数

#include <iostream>
using namespace std;
const int N=1e5+10;
int a[N],b[N],c[N];
int cnt1[N],cnt2[N];
int s1[N],s2[N];
int main(){
    int n;
    scanf("%d",&n);
    int w=3;
    int min1=N,max1=0;
    while(w){
       for(int i=1;i<=n;i++){
           if(w==3){
               scanf("%d",&a[i]);
               cnt1[a[i]]++;
               min1=min(min1,a[i]);
               max1=max(max1,a[i]);
           }
           
           if(w==2){
               scanf("%d",&b[i]);
               min1=min(min1,b[i]);
               max1=max(max1,b[i]);
           }
           if(w==1){
               scanf("%d",&c[i]);
               cnt2[c[i]]++;
               min1=min(min1,c[i]);
               max1=max(max1,c[i]);
           }
       } 
       w--;
    }
    //注意min,max必须覆盖全部数字
    for(int i=min1;i<=max1;i++){
        s1[i]=s1[i-1]+cnt1[i];
    }
    for(int i=min1;i<=max1;i++){
        s2[i]=s2[i-1]+cnt2[i];
    }
    long long ans=0;
    for(int i=1;i<=n;i++){
        int l=s1[b[i]-1];
        int r=s2[max1]-s2[b[i]];
        //这里必须进行强转
        if(l>0&&r>0)ans+=(long long)l*r;
    }
    printf("%lld",ans);
    
    return 0;
}

法二:排序加二分 O(nlogn)

#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5+100;
int a[N],b[N],c[N];
int n;
int searchl(int x){
    int l=0,r=n-1;
    while(l<r){
        int mid=(l+r+1)/2;
        if(a[mid]<x)l=mid;
        else r=mid-1;
    }
    if(a[l]<x)return l;
    else return -1;
}
int searchr(int x){
    int l=0,r=n-1;
    while(l<r){
        int mid=(l+r)/2;
        if(c[mid]>x)r=mid;
        else l=mid+1;
    }
    if(c[l]>x)return l;
    else return -1;
}
int main(){

    scanf("%d",&n);
    int w=3;
    long long  ans=0;
    while(w--){
       for(int i=0;i<n;i++){
          if(w==2)scanf("%d",&a[i]);
          if(w==1)scanf("%d",&b[i]);
          if(w==0)scanf("%d",&c[i]);
       } 
    }
   //二分的前提是有序
    sort(a,a+n);
    sort(b,b+n);
    sort(c,c+n);
   
    for(int i=0;i<n;i++){
        int l=searchl(b[i]);
        int r=searchr(b[i]);
        
        if(l!=-1&&r!=-1){
       //不能写成(long long)((l+1)*(n-r));
            ans+=(long long)(l+1)*(n-r);
        }
        
    }
    printf("%lld",ans);
    return 0;
}

法三:双指针
最后一个样例会运行超时

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long LL;
const int N = 1e5+10;
int num[3][N];

int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < 3; ++i) 
        for(int j = 1; j <= n; ++j) 
            scanf("%d", &num[i][j]);
    for(int i = 0; i < 3; ++i)
        sort(num[i]+1, num[i]+n+1);

    LL ans = 0;
    //枚举B,寻找A满足的个数以及C满足的个数相乘
    int a = 1, c = 1;
    for(int i = 1; i <= n; ++i) {
        int key = num[1][i];
        while(a<=n && num[0][a] < key) a++;
        while(c<=n && num[2][c] <= key) c++;

        ans += (LL)(a-1)*(n-c+1);

    }
    cout<<ans<<endl;
    return 0;
}

5.外卖店优先级

在这里插入图片描述

坑点
首先 设定的数值就很有意思
value<=3的时候 从缓冲队列释放 value>5的时候 放入缓冲队列
每次有外卖的时候加2分
那如果我value=3 不是刚好卡在中间??
这也是优先级减小和优先级增加的先后顺序 会对结果产生影响的原因

详细解释
假设当前节点为id 且当前时间点刚开始的时候 优先级为3
且节点id之前在缓冲队列中 满足f[id]=1

1.正常流程
因为时间点刚开始的时候 优先级为3
节点id从队列中释放f[id]=0
然后有外卖订单 优先级变为5 f[id]仍保持为从1变成0的结果

2.若先加分再判断
那么相当于时间点刚开始的时候
我们就有了3+2=5的优先级
f[id]=1的结果不变

也就是造成了影响!!!!!

所以这道题目一定要想清楚
判断是否出队是在时间点刚开始的时候!!
优先级增加是在时间点结束的时候!!!

#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5+100;
struct Node{
   int ts,id;
   bool operator <(const Node &node)const{
      return id<node.id||id==node.id&&ts<node.ts;
   }
}node[N];
bool st[N];//是否在缓存
int priority[N];//优先级
int pre[N];//上一次时间
int main()
{
  int n,m,t;
  long long ans=0;
  scanf("%d%d%d",&n,&m,&t);
  for(int i=0;i<m;i++){
    scanf("%d%d",&node[i].ts,&node[i].id);
  }
  sort(node,node+m);
  for(int i=0;i<m;i++){
    int ts=node[i].ts;
    int id=node[i].id;
    
    //printf("id=%d\n",id);
    //printf("ts=%d\n",ts);
    //注意处理的顺序
    if(pre[id]!=ts)priority[id]-=ts-pre[id]-1;
    priority[id]=max(0,priority[id]);
    if(priority[id]<=3)st[id]=false;

    priority[id]+=2;
    if(priority[id]>5)st[id]=true;

    pre[id]=ts;
  }
  //printf("pre1=%d\n",pre[1]);
  for(int i=1;i<=n;i++){
    if(pre[i]<t){
       //注意这里一定会少所以多减一个1
       priority[i]-=t-pre[i];
    }
    if(priority[i]<=3)st[i]=false;
  }

  for(int i=1;i<=n;i++){
    if(st[i]){
        //printf("%d\n",i);
        ans++;
    }
  }
  printf("%d",ans);
  return 0;
}

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
鉴于提供的内容是一段包含三个不同的Java程序的代码,我无法提供一个完整的答案来回答你的问题。但是,我可以为你提供一些信息。 根据引用和引用的内容,这两个程序都涉及到动态规划算法。引用中的程序解决了一个关于序列的最长递增子序列的问题,而引用中的程序解决了一个关于背包问题的二维动态规划的问题。 对于引用中的内容,它是一个程序解决的是一个最长上升子序列的问题。 根据提供的代码,这些程序可能是用来解决一些蓝桥杯竞赛的题目。然而,我无法提供更多关于具体问题的信息。 如果你需要帮助解决特定的问题,我建议你仔细阅读每个程序的代码并理解它们的功能,然后根据需要进行相应的修改。如果你有关于动态规划蓝桥杯竞赛的更具体的问题,我会很愿意帮助你。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [蓝桥杯AcWing学习笔记 3-2简单DP的学习(附相关蓝桥真题:地宫取宝、波动数列)(Java)](https://blog.csdn.net/weixin_53407527/article/details/123122245)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值