(220608学习记录 (也就是昨天做的题) 是220502 学习记录的后三道题)
B. 炸鸡块君与FIFA22 B-炸鸡块君与FIFA22
题解:
文章图片
首先是st表部分,分为建表和查询两部分。参考:算法学习笔记(12): ST表 - 知乎 (zhihu.com)
Part1 st建表首先把所有数据都放入f[i][0]中。一代目是找到以 j 开头的,
文章图片
区间的最大的数,也就是拿
文章图片
和
文章图片
取最大;二代目是找到以 j 开头的,
文章图片
区间的最大的数,也就是拿
文章图片
和
文章图片
取最大;三代目是找到以 j 开头的,
文章图片
区间的最大的数,也就是拿
文章图片
和
文章图片
取最大……如此持续i遍。
int f[MAXN][21];
// f[a][b]中a是总数,b是关于区间的
for (int i = 1;
i <= n;
++i)
f[i][0] = read();
// 读入数据,自己的数据
for (int i=1;
i<=20;
++i)
for (int j=1;
j+(1<
Part2 st查表查询[ l , r ]区间时,找到这个区间的两个的子区间,它们的并集恰是[ l , r ]。目标是找到区间
文章图片
和区间
文章图片
,要求
文章图片
尽量靠 r,因此
文章图片
。
算log时的O(n)预处理:
for (int i=2;
i<=n;
++i)Log2[i]=Log2[i/2]+1;
//Log2是数组
查询代码如下:
for (int i = 0;
i < m;
++i){
int l = read(), r = read();
int s = Log2[r - l + 1];
printf("%d\n", max(f[l][s],f[r-(1<
Part3 解题 【学习|20220609学习记录(st表、动态规划、数学)】首先是初始化,把每个变化量都放在三维数组里
for(int i=1;
i<=n;
i++){//初始化
if(s[i]=='W')f[0][i][0]=f[1][i][0]=f[2][i][0]=1;
if(s[i]=='L')f[1][i][0]=f[2][i][0]=-1;
}
之后是建表,设起始分数为a,现在的分数的变化量等于 a加上一轮的分数变化量为起点的 后一半变化量。
for (int i=1;
i<=20;
++i)
for (int j=1;
j+(1<
最后是查询部分,l逐渐靠近,然后把每个部分的分数都加上。
while(q--){
int l,r,ss;
cin>>l>>r>>ss;
int res=ss;
int tmp=ss%3;
for(int i=20;
i>=0;
i--){
if((l+(1<
全部代码:
#include
using namespace std;
int f[5][200005][25];
int main()
{
int n,q;
cin>>n>>q;
string s;
cin>>s;
s=" "+s;
for(int i=1;
i<=n;
i++){//初始化
if(s[i]=='W')f[0][i][0]=f[1][i][0]=f[2][i][0]=1;
if(s[i]=='L')f[1][i][0]=f[2][i][0]=-1;
}
for (int i=1;
i<=20;
++i)
for (int j=1;
j+(1<>l>>r>>ss;
int res=ss;
int tmp=ss%3;
for(int i=20;
i>=0;
i--){
if((l+(1<
K. 冒险公社 K 冒险公社
文章图片
dp[now][i][j][k]表示当前第now个岛,i是当前岛颜色,j是前一个岛颜色,k是前前一个岛颜色。
Part1 初始化 首先是前三座岛屿初始化, 把三座岛27种可能全部都列出来,注意只有符合条件的才能放出来
for(int i=1;
i<4;
i++)
for(int j=1;
j<4;
j++)
for(int k=1;
k<4;
k++){
int g=0,r=0,b=0;
if(i==1)g++;
if(j==1)g++;
if(k==1)g++;
if(i==2)r++;
if(j==2)r++;
if(k==2)r++;
if(i==3)b++;
if(j==3)b++;
if(k==3)b++;
if(g>r&&s[3]=='G')dp[3][i][j][k]=g;
//符合情况
if(g==r&&s[3]=='B')dp[3][i][j][k]=g;
if(g
Part2 动态规划 把当前岛的27个情况都列出来,这个地点的状态是由上一个状态转移过来的。
设当前状态是{i j k},根据 j k状态去找 now-1 状态的{j k l}。当 i 是绿色的时候,dp值在now-1上+1;如果不是,now的量等于now-1的量。
for(int now=4;
now<=n;
now++){
for(int i=1;
i<4;
i++)
for(int j=1;
j<4;
j++)
for(int k=1;
k<4;
k++){
int g=0,r=0,b=0;
if(i==1)g++;
if(j==1)g++;
if(k==1)g++;
if(i==2)r++;
if(j==2)r++;
if(k==2)r++;
if(i==3)b++;
if(j==3)b++;
if(k==3)b++;
for(int l=1;
l<=3;
l++){
if(g>r&&s[now]=='G')
dp[now][i][j][k]=max(dp[now][i][j][k],dp[now-1][j][k][l]+(i==1));
if(g==r&&s[now]=='B')
dp[now][i][j][k]=max(dp[now][i][j][k],dp[now-1][j][k][l]+(i==1));
if(g
最后取最大就可以了。
代码:
#include
using namespace std;
int dp[100005][4][4][4];
//现在,岛现在,前一个岛,前前一个岛
int main()
{
int n;
cin>>n;
memset(dp,-0x3f,sizeof(dp));
string s;
cin>>s;
s=" "+s;
for(int i=1;
i<4;
i++)
for(int j=1;
j<4;
j++)
for(int k=1;
k<4;
k++){
int g=0,r=0,b=0;
if(i==1)g++;
if(j==1)g++;
if(k==1)g++;
if(i==2)r++;
if(j==2)r++;
if(k==2)r++;
if(i==3)b++;
if(j==3)b++;
if(k==3)b++;
if(g>r&&s[3]=='G')dp[3][i][j][k]=g;
//符合情况
if(g==r&&s[3]=='B')dp[3][i][j][k]=g;
if(gr&&s[now]=='G')
dp[now][i][j][k]=max(dp[now][i][j][k],dp[now-1][j][k][l]+(i==1));
if(g==r&&s[now]=='B')
dp[now][i][j][k]=max(dp[now][i][j][k],dp[now-1][j][k][l]+(i==1));
if(g
G ACM is all you need G-ACM is all you need
因为是对所有的函数值进行
文章图片
,所以后面的b其实不重要,重要的是看绝对值里面的部分。
part1 算距离求区间 找到每三个点当中最中间的点不是局部最小点的b的区间范围,其实就是计算a[i]到b的距离。
三个点是低中高三者的排列组合,一共有6种情况。如果连续的两个点高度相等,那么它们绝对不会是局部最小点,所以不用计算在内。
例如三个点是 左高中中右低 这种情况,那么此时b的选择范围有两个,分别是
文章图片
到
文章图片
(加1是因为b是整数,而且保证中间不是局部最小)和
文章图片
到
文章图片
。
但这六种情况可以通过min和max合并成3种情况,如代码所示。
Part2 计算区间覆盖最多的数 现在有很多区间,要计算区间覆盖最多的数。如下图所示,区间的左端点记为+1,右端点的下一个点记为-1,如此每个点从小到大顺下去加减,这样就能求出每个点被区间覆盖的次数。
用map实现。
文章图片
Part3 求点 可以看到,本来是局部最小点的区间都是x到正无穷,其他两种本来就不是局部极小值的点都是有负无穷到x的。
于是在计算的时候,设本来就是局部极小的点有ans个,区间覆盖的最大次数为sum。
如果取到的这个b刚好让一个不是局部极小的点p变成局部极小了,那么这个sum肯定会先对点p这个区间右端点减去1了。所以最终的答案是ans-sum。
代码:(当然还有一种解法是找出中间的点是局部极小点的区间,然后求区间覆盖的最少,但这里不做了)
#include
using namespace std;
int a[100005];
map mp;
int main()
{
int T;
cin>>T;
while(T--){
mp.clear();
int n;
cin>>n;
int ans=0;
for(int i=1;
i<=n;
i++){cin>>a[i];
}
for(int i=2;
i<=n-1;
i++){
if(a[i]a[i+1]&&a[i]>a[i-1]){//防止转换后,中间的点变小了
int r=(a[i]+max(a[i-1],a[i+1]))/2;
//到无限小
mp[r+1]--;
//--方面一定是+1后计算的
}
else if(a[i]>a[i+1]&&a[i]a[i-1]){
//防止转换后,中间的点变小了
int l=(a[i]+max(a[i-1],a[i+1])+1)/2;
//到无限大
mp[l]++;
int r=(a[i]+min(a[i-1],a[i+1]))/2;
//到无限小
mp[r+1]--;
}
}int res=0,sum=0,a=0;
for(auto i:mp){res+=i.second;
sum=max(sum,res);
}
cout<
推荐阅读
- c++|c++运算符重载
- 单细胞|2022.04.13【读书笔记】|10X单细胞转录组分析流程介绍
- 大数据-零基础学习|第11期(Hadoop零基础学习路线)
- 机器学习吴恩达|coursera机器学习吴恩达-学习笔记-第三周
- 算法开胃小菜
- 目标检测算法之YOLOv3及YOLOV3-Tiny
- python|全国大学生计算机等级考试计算机二级python真题
- python|计算机二级Python真题(十二)
- 算法|工程详细记录(超准确人脸检测(带关键点)YOLO5Face C++)