当前位置: 首页 > news >正文

2021市赛复赛 初中组

思路详解在注释 

1. T1:数字统计(count)

     给定两个整数n和x,计算在区间1到n的所有整数中(无前导零十进制表示),数字x一共出现的次数。
签到题,暴力即可  代码不放了

2. T2:次大值求和(sum)

    给定一个1到n的数字各出现一次的排列a[1]、a[2]、…、a[n],定义f(l,r)表示a[l]、a[l+1]、a[l+2]、…、a[r]中的次大值,你需要求出对于所有的1<=i<j<=n,f(i,j)的和。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,l[N],r[N];
ll ans;
struct sty{int x,id;
}a[N];
bool cmp(struct sty x,struct sty y){return x.x<y.x;
}
/*
考虑 30pts 的作法我们可以直接枚举每个区间的左右端点 l r,
然后用 O(n) 的时间求出次大值并累加,时间复杂度 O(n^3)。
然后我们会发现一个区间的次大值可以由上一个区间转移过来,
故可以将时间复杂度优化为 O(n^2),期望得分 70pts。
可以观察到之前我们所有的算法思想无外乎是以统计区间为主的。
这里我们转化一下思想,我们其实可以枚举每一个数作为次大值时是哪些区间。
当一个数作为次大值时。设她右边第一个比她大的数与她的距离为 d1 ,
设左边第一个比她大的数与她的距离为 d2 。
则所有以她为次大值的区间个数就是 d1(d2-1)+d2(d1-1)->乘法原理。
内心:看不懂一点公式…………………………
但是找到某个数左边的比她大的数和右边比她大的数又要花费我们 O(n) 的时间,
考虑如何优化:其实可以用单调队列等多种数据结构优化,但我这边用的是双向链表:
我们先排序,然后从小到大枚举,每枚举完一个数就将这个数删掉,
容易发现这时每个数左边第一个数便是原数列中第一个她大的,右边同理。
时间复杂度 O(nolgn+n) 期望得分 100pts
*/ 
int main(){scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i].x); //第i个数对应的值 a[i].id=i; //第几个数 }sort(a+1,a+n+1,cmp); //按照值从小到大进行排序 for(int i=1;i<=n;i++) {l[i]=i-1,r[i]=i+1; //初始化i的左边和i右边的值 } r[n+1]=n+1;//防止在查询右操作(就是右边的右边)时,k2=0,但左操作不会 
//	for(int i=0;i<=n+1;i++){
//		printf("%d %d\n",l[i],r[i]);
//	} for(int i=1;i<=n;i++){int x=a[i].id; int j1=l[x];//当前的左边 int j2=l[j1];//当前的左边的左边int k1=r[x];//当前的右边int k2=r[k1];//当前的右边的右边      l[r[x]]=l[x];r[l[x]]=r[x];//删除当前节点 
//      for(int i=0;i<=n+1;i++){
//		printf("\n%d %d\n",l[i],r[i]);
//	} ans=ans+(ll)i*((j1-j2)*(k1-x)+(k2-k1)*(x-j1));/*为什么要乘i,因为当你在第i小时,只可能有i种选择例:4 2 3 1 ----> 1 2 3 4所在区间次大值是1:1 2所在区间次大值是2: 2 3 / 1 2 3所在区间次大值是3: 3 4 / 2 3 4 / 1 2 3 4所在区间次大值是4:无,因为他最大,虽然看上去乘了,但由于 (j1-j2)*(k1-x)+(k2-k1)*(x-j1)一定为 0,等于没有乘 d1(d2-1)+d2(d1-1):举个例子:2(l2) 0 3(l1) 1(x) 0 2(r1) 3(r2)l1-l2意思是i左侧当i作为次大值是有几个区间,r1-x意思是既然在左侧i已经为次大值了,那么在右侧一直到下一个比它大的值之前的所有区间即为所求(因为从大到小,下一个i连的点即为比它大的点)加号右侧相反,同理*/}printf("%lld\n",ans);return 0;
}


3. T3:优先队列题

     给定n个整数a[i]和一个整数m,对于所有1<=i<=n和1<=j<=n,求出a[i]+a[j],然后将所有求得的n^2个a[i]+a[j]的数值从大到小排序,你需要求出排序后前m个数的和。

思路:把ai+aj的和放进队列,当数量大于m后,剔除最小的,而ai+aj<q.top()时,说明接下来的ai+aj都小于q.top(),直接退出即可,这样使时间复杂度降低

     代码:

#include <bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int> >q;
int a[100001];
bool cmp(int a,int b) {return a>b;
} 
int main(){int n,m;long long ans=0;cin>>n>>m;for(int i=1;i<=n;i++)scanf("%d",&a[i]);sort(a+1,a+1+n,cmp);int Size=0;for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){q.push(a[i]+a[j]);Size++;if(Size>m){q.pop();if(a[i]+a[j]<q.top()) break;}}} while(!q.empty()) ans+=q.top(),q.pop();cout<<ans;return 0;
}


4. T4 backpack

    给定n个物品和一个整数s,第i个物品的体积是a[i],定义f(l,r)表示在第l个物品到第r个物品中选出若干个物品的方案数,使得这些物品的体积之和为s。
你需要求出对于所有1<=l<=r<=n,f(l,r)的和。由于答案可能很大,你只需要输出答案对998244353取模的结果。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=998244353,N=3e3+10;
int n,a[N],s,f[N][N];
ll ans=0;
/*这代码的恶心点在于它的i指的不是平时的1~i中有几种可能性
而是1~i、2~i、……、i~i共i组可能性的和 
而且,它还代表了1~i+1、2~i+1……1~i+2、2~i+2…………
中只使用这i组时的所有可能性 */
int main(){cin>>n>>s;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++){for(int j=1;j<=3000;j++){//循环背包容量//但是我还是认为j到s就行了
//		如果容量刚好能放下这个物品时,光放这一个的可能性
//		一开始我也没看懂,但是悟了之后其实就很明显了:
//		加i是因为f[i][j]中共有i组,每组多一种可能性,便是i种if(j==a[i]) f[i][j]=(f[i][j]+i)%mod;//等于if(j==a[i]) Add(f[i][j],i); //没放的可能性 ,dp板子 f[i][j]=(f[i][j]+f[i-1][j])%mod;//等于Add(f[i][j],f[i-1][j]);//只要能放进去了总可能性中就一定会有没有a[i]时的方案数,所以加上if(j>=a[i]) {f[i][j]=(f[i][j]+f[i-1][j-a[i]])%mod; }//如果背包放满了,记录答案//*n-i+1是把所有含这i组且只用这i组中的可能性一口气加上 //因为直接一口气加上了,所以-f[i-1][j]防止重复加 if(j==s) {ans=(ans+(1ll*(f[i][j]+mod-f[i-1][j])%mod*(n-i+1)%mod)%mod)%mod;}//1ll意思是运算中可能会超int,所以运算中先开成long long,运算结束后//再赋值回int,防止爆掉(实际看代码时当不存在就好了) }}cout<<ans<<endl;return 0;
}
http://www.dtcms.com/a/284132.html

相关文章:

  • 保持视频二维码不变,如何更新视频内容,节省物料印刷成本
  • 氧化锌避雷器具备的功能
  • Redis原理之主从复制
  • Visual Studio 的常用快捷键
  • 7.17 Java基础 | 集合框架(下)
  • 数据结构 栈(2)--栈的实现
  • NO.7数据结构树|线索二叉树|树森林二叉树转化|树森林遍历|并查集|二叉排序树|平衡二叉树|哈夫曼树|哈夫曼编码
  • 突破AI模型访问的“光标牢笼”:长上下文处理与智能环境隔离实战
  • 网络基础11 上公网--Internet接入技术
  • 扣子工作流的常见节点
  • AutoGen-AgentChat-13-多智能体相互辩论
  • 船舶机械零件的深孔工艺及检测方法 —— 激光频率梳 3D 轮廓检测
  • istio如何自定义重试状态码
  • JAVA面试宝典 -《缓存架构:穿透 / 雪崩 / 击穿解决方案》
  • JVM 内存分配与垃圾回收策略
  • Java学习--JVM(2)
  • Java面试(基础篇) - 第二篇!
  • 如何用 Python + LLM 构建一个智能栗子表格提取工具?
  • Spring,Spring Boot 和 Spring MVC 的关系以及区别
  • 深入解析Hadoop:机架感知算法与数据放置策略
  • #Linux内存管理# vm_normal_page()函数返回的什么样页面的struct page数据结构?为什么内存管理代码中需要这个函数?
  • 【机器学习】第三章 分类算法
  • 如何判断你的EDA工具安装是否真的成功?
  • 数据呈现:让图表说话,从数字到洞察的可视化艺术
  • “显著性”(Saliency)是计算机视觉中的一个重要概念,主要指的是图像或视频中最吸引人注意力的区域或对象
  • Python进阶操作——创建容器
  • Ubuntu开启root用户登陆
  • MyBatis延迟加载(Lazy Loading)之“关联查询”深度解析与实践
  • ros0基础-day13
  • java之json转excel生成