A
A-自动收小麦机_2023河南萌新联赛第(二)场:河南工业大学 (nowcoder.com)
看到需要求和的时候,也别是这种范围不是那么小的,就要想到用前缀和来实现,先用前缀和将每个高度对应的小麦的数量求出来。
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
其次,我们要算出在每个格子上面放水的时候对应的小麦数量,在以后的查询中更加方便,减少时间复杂度,那么我们应该怎样求出每个高度对应的小麦数量呢,分为两种情况,第一种:当从该位置流经k个格子时,没有遇见比当前高度低的,也就是高度一样,第二种:当从该位置流经k个格子时,遇见比当前高度低的。不难发现两种情况都出现了比当前高度低的字眼,那么我们是不是要求一下比当前高度低的位置的坐标呢,遇见比当前高度低的就记下它的坐标。那么这个问题解决了。
最后我们应该怎样算出每个位置的小麦数量呢?对于第一种情况,我们直接可以用当前位置的小麦数量减去流经k个位置到达的格子的小麦的数量,得到的不就是从当前位置流经k个格子之后的小麦数量。对于第二种情况:要先算出该位置到比它低的位置的小麦数量,也就是sum[i]-sum[flag],最后还要加上你降低高度之后又流经k个格子对应的最终小麦数量。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll sum[100009],a[100009],h[100009],ans[100009];
int n,q,k;
void find()
{
int flag=-1;
for(int i=1;i<=n;i++)
{
if(i==1) ans[i]=sum[i];
else
{
if(h[i]>h[i-1])
flag=i-1;
if(i-k<flag) //说明向前流k个格子的时候有比当前高度低的
ans[i]=sum[i]-sum[flag]+ans[flag];
else //没有比当前高度低的
ans[i]=sum[i]-sum[i-k];
}
}
}
int main()
{
cin>>n>>q>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
// for(int i=1;i<=n;i++)
// cout<<sum[i]<<endl;
for(int i=1;i<=n;i++)
{
cin>>h[i];
}
find();
while(q--)
{
int y;
cin>>y;
cout<<ans[y]<<endl;
}
return 0;
}
D
D-固执的RT_2023河南萌新联赛第(二)场:河南工业大学 (nowcoder.com)
计算收集的树枝的攻击力之和是否满足最低要求。
代码:
#include<bits/stdc++.h>
using namespace std;
int a[100009];
int main()
{
int n,m;
long long sum=0;
cin>>n>>m;
int f=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
if(sum>=m)
{
f=1;
break;
}
}
if(f) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
E
E-释怀的RT_2023河南萌新联赛第(二)场:河南工业大学 (nowcoder.com)
题目意思很好理解,就是往两边分别照亮a[i]个距离,看最后有几个格子被照亮,如果遇见一个数就往两边遍历看是否会被点亮是会超时的,我们可以先从左向右遍历,被照亮的标记一下,在从右向左遍历,被照亮的在标记一下,这样就会大大减少时间复杂度。
对于更新距离举一个例子:例如 0 1 5 0 0,刚开始遇到1,距离u为1,遍历到5时候u--,u为0,此时向右遍历的范围从之前的1变成了现在的5,所以距离要更新。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[1000009];
ll vis[1000009];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
ll ans=0;
//向右遍历一遍
ll u=0;//距离
for(int i=1;i<=n;i++)
{
if(!vis[i]&&u)//没有被标记过并且遍历的距离不为0
{
ans++;
vis[i]=1;
}
u--;
if(a[i]>u) u=a[i]; //遇见照亮范围更大的,更新距离的值
}
//向左遍历一遍
u=0;
for(int i=n;i>=1;i--)
{
if(!vis[i]&&u)
{
ans++;
vis[i]=1;
}
u--;
if(a[i]>u) u=a[i];
}
cout<<ans<<endl;
return 0;
}
G
G-爬山_2023河南萌新联赛第(二)场:河南工业大学 (nowcoder.com)
因为缆车越高攀爬高度越低,符合二分单调性,计算过程中要开long long。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[100009];
int n,p;
bool find(int h)
{
ll sum=0;
for(int i=1;i<=n;i++)
{
if(a[i]>h)
sum+=a[i]-h;
}
return sum*2>=p;
}
int main()
{
cin>>n>>p;
ll sum=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
if(sum*2<p) //当缆车高度为0的时候还小于运动指标
{
cout<<"-1"<<endl;
return 0;
}
int l=0,r=0x3f3f3f3f;//开的大一点
while(l<=r)
{
int mid=(l+r)/2;
if(find(mid)) l=mid+1;
else r=mid-1;
}
cout<<l-1<<endl;
return 0;
}
I
I-奶牛的寿命_2023河南萌新联赛第(二)场:河南工业大学 (nowcoder.com)
题目中说是交换次数不超过log2(n)+1次,其实也就是次数不超过十进制数转换为二进制数的位数,但是由于没有前导0,所以最多交换len-1次,所以这个次数没有影响。
想要减刑时间长,那么我们就让高位的1与0交换,首先我们要将输入的十进制数转换为二进制,接着开始交换,交换完毕之后将二进制数重新转换为十进制数即可。
代码:
#include<bits/stdc++.h>
using namespace std;
string dict = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string ten(long long n) //十进制转 x 进制函数。
{
string ans = "";//将字符串为空
while (n != 0) //模拟短除法。
{
ans += dict[n % 2];
n /= 2;
}
string t = ""; //倒取余数。
for (int i = ans.size()-1; i >= 0; i--)
t += ans[i];
return t;
}
int main()
{
long long n;
cin>>n;
string s;
s=ten(n);
//cout<<s<<endl;
long long len=s.size();
long long t=0;
for(int i=1;i<len;i++)
{
if(s[i]=='0')
{
s[i]='1';
t++;
}
}
int j=1;//最高位0不用交换
while(t--)
{
s[j]='0';
j++;
}
//cout<<s<<endl;
long long sum=0,k=1;
for(int i=len-1;i>=0;i--)
{
sum+=(s[i]-'0')*k;
k*=2;
}
cout<<n-sum<<endl;
return 0;
}