2023河南萌新联赛第(六)场:河南理工大学

目录

A 简单的异或

题目:

解析:

B 这是dp题吗

题目链接:https://ac.nowcoder.com/acm/contest/63602/B

解析:

D 买饼干的小Y

题目:https://ac.nowcoder.com/acm/contest/63602/D

解析:

E 不爱吃早饭的小Y

题目:https://ac.nowcoder.com/acm/contest/63602/E

解析:

H 左右横跳

题目:https://ac.nowcoder.com/acm/contest/63602/H

解析:

I 简单的组合

题目:https://ac.nowcoder.com/acm/contest/63602/I

解析:

J 线代高手

题目:https://ac.nowcoder.com/acm/contest/63602/J

解析:

L 阴晴不定的大橘学长

题目:https://ac.nowcoder.com/acm/contest/63602/L

解析:

A 简单的异或

题目:

  小Y学过异或后觉得这太简单了,但小H认为小Y太天真了,决定考验一下他,出了一道题:
    给出一个数组a,长度为n,分别为a1​,a2​,a3​,...an−1​,an​。以及q次访问,每次给出两个整数 l,r表示区间的左右端点。

    对于每次访问,给出一个整数 x(x<2^31) 使∑i=l r​(x⊕ai​)最大 

输入描述:

第一行一个整数N (1≤N≤10^5),表示序列的长度
第二行N个整数,表示序列内的元素(1≤ai​<2^31)
第三行一个整数q,表示询问的个数(1≤q≤10^5)

接下来q行,每行两个整数 L,R,表示询问的区间

保证L≤R

输出描述:

对于每次访问输出一个对应的x,若有多个解则输出最小的解

示例1

输入

5
1 2 3 4 5
3
1 2
2 4
3 5

输出

2147483644
2147483645
2147483642

说明

第一个样例中,

第一次访问区间[1,2]

区间内的值为1,2

当x取2147483644即1111111111111111111111111111100(31位二进制)时

x^1+x^2的值最大

解析:

题意就是求一个x , 使得区间内每一个元素与 x异或后的总和最大
先考虑单个元素与 x异或后最大,根据异或的性质,容易得到x 应该和 a的每一位都相反,才能
使得异或值最大。
考虑区间大小大于等于2 ,假如区间内每个元素的二进制第 i位相同 ( 从右往左数 ) ,比如全为1 ,那么
当 x的第 i位取相反值 0时,该位对于最后的总和贡献就是n*2^(i-1)
( 表示元素的个数 ) ,每有一个元素
的二进制第 i位为0 ,该位的贡献就会减少 2^(i-1)
,当有超过n/2的元素该位上为 0时, 的该位上取1 贡献更大
所以贪心考虑 x上每一位取值 0/1的贡献的多少,选择贡献大的即可
区间内第 i 位上 0 的个数与 1 的个数,当 1多时 x的第 i位上取0 , 0多则取 1。
特别的当 0和 1的数量相同时,因为题目要求输出较小值,取0 即可
暴力计算区间内第 i 位上的 1 个数求解复杂度 利用前缀和优化求解复杂度
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[100010][40],sum[100010][40];
void solve()
{
	int n,q,l,r;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i][0];
		for(int j=1;j<=31;j++)
		{
			a[i][j]=a[i][0]>>(j-1)&1;
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=31;j++)
		{
			sum[i][j]+=a[i][j]+sum[i-1][j];
		}
	}
	cin>>q;
	while(q--)
	{
		int x=0;
		int ans;
		cin>>l>>r;
		for(int i=1;i<=31;i++)
		{
			ans=sum[r][i]-sum[l-1][i];
			if(ans<r-l+1-ans)
			x+=1<<(i-1);
		}
		cout<<x<<endl;
	}
}
signed main()
{
	int t=1;
	//cin>>t;
	while(t--)
	solve();
	return 0;
}

B 这是dp题吗

题目链接:https://ac.nowcoder.com/acm/contest/63602/B

解析:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
const int N=1e3+7;
int a[N][N];
void solve(){
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++) 
	{
		for(int j=0;j<=2*n;j++) 
		a[i][j]=-1e18;
		for(int j=n-i+1;j<=n+i-1;j++)
		cin>>a[i][j];
	}
	for(int i=1;i<=n;i++) 
	{
		for(int j=n-i+1;j<=n+i-1;j++) 
		{
			a[i][j]+=max(a[i-1][j],max(a[i-1][j-1],a[i-1][j+1]));
		}
	}
	int ans=-1e18;
	for(int j=n-k;j<=n+k;j++) 
	ans=max(ans,a[n][j]);
	cout<<ans<<endl;
}
signed main()
{
	IOS
	int t=1;
	//cin>>t;
	while(t--)
	solve();
	return 0;
}

D 买饼干的小Y

题目:https://ac.nowcoder.com/acm/contest/63602/D

解析:

先暴力找到力气大于等于1的,之后加上剩下的(不足一的按1计算)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int a[202000];
void solve()
{
	int n,m,x,y,sum=0;
	cin>>n>>m;
	x=n;
	y=m;
	x-=m;
	while(x>0)
	{
		x-=ceil((double)y/2);
		sum++;
		y=ceil(double(y)/2);
		if(y<=2&&x>0)
		{
			sum+=x;
			x=0;
		}
	}
	cout<<sum<<endl;
	return ;
}
signed main()
{
	IOS
	int t=1;
	//cin>>t;
	while(t--)
	solve();
	return 0;
}

E 不爱吃早饭的小Y

题目:https://ac.nowcoder.com/acm/contest/63602/E

解析:

对于单堆饼干暴力或者递归求出该堆的SG函数值,如果为0 ,先手必败,反之先手必胜。对于n 堆游戏,总游戏的合就是每个单堆的SG函数的异或和

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
void solve()
{
	int n,a,b;
	cin>>n>>a>>b;
    int res=0;
    for(int i=0;i<n;i++){
        int x;
        cin>>x;
        x%=(a+b);
        res^=x/a;
    }
    cout<<(res?"C":"Y");
	return ;
}
signed main()
{
	IOS
	int t=1;
	//cin>>t;
	while(t--)
	solve();
	return 0;
}

H 左右横跳

题目:https://ac.nowcoder.com/acm/contest/63602/H

解析:

简单的动态规划,题目可以理解为一个 n*m 大小的点阵,每个点上有不同的分数,而一个点上能得 到的分数或积累的分数需要通过操作一直接继承正下方的点的分值,或者通过操作二继承下方任意一列 的间隔 k 行的点的分数并加上所在位置上点的分数 ,因为通过操作二转移得到的分数需要比较 m 列所有的分数,所以每操作一行就记录当前一行所能获得的分数的最大值
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int a[100010],dp[100010];
void solve()
{
	int n,m,k,sum=0,x,num=0,j=1;
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
	    {
		cin>>x;
		a[i]=max(a[i],x);
	    }
	}
	dp[1]=a[1];
	for(int i=2;i<=n;i++)
	{
		dp[i]=dp[i-1];
		if(i-k>0)
		dp[i]=max(dp[i],dp[i-k]+a[i]);
	}
	cout<<dp[n]<<endl;
	
}
signed main()
{
	IOS
	int t=1;
	//cin>>t;
	while(t--)
	solve();
	return 0;
}

I 简单的组合

题目:https://ac.nowcoder.com/acm/contest/63602/I

解析:

string模拟排序,输出值即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
bool cmp(string x,string y)
{
	return x>y;
}
void solve()
{
	int n,sum=0,num=0;
	cin>>n;
	string a,b,c,d;
	string z[5];
	for(int i=31;i>=0;i--)
	{
		int k=n>>i&1;
		sum++;
		if(sum<=8)
		z[0]+=(k+'0');
		else if(sum<=16)
		z[1]+=(k+'0');
		else if(sum<=24)
		z[2]+=(k+'0');
		else
		z[3]+=(k+'0');
	}
	sort(z,z+4,cmp);
	for(int i=0;i<4;i++)
	{
		for(int j=0;j<8;j++)
		{
			num=num*2+(z[i][j]-'0');
		}
	}
	cout<<num<<endl;
}
signed main()
{
	IOS
	int t=1;
	//cin>>t;
	while(t--)
	solve();
	return 0;
}

J 线代高手

题目:https://ac.nowcoder.com/acm/contest/63602/J

解析:

数据范围较小,直接暴力枚举左上角和右下角,如果该子矩阵合法,更新答案即可
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
signed main() {
	IOS
    int n, m;
    cin >> n >> m;
    vector<int> A(n);
    for (int i = 0; i < n; ++i) {
        cin >> A[i];
    }
    vector<int> B(m);
    for (int i = 0; i < m; ++i) {
        cin >> B[i];
    }
    int x;
    cin >> x;
    int maxArea = 0;
    vector<int> prefixSumA(n + 1, 0);
    vector<int> prefixSumB(m + 1, 0);
    for (int i = 1; i <= n; ++i) {
        prefixSumA[i] = prefixSumA[i - 1] + A[i - 1];
    }
    for (int i = 1; i <= m; ++i) {
        prefixSumB[i] = prefixSumB[i - 1] + B[i - 1];
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            for (int k = i; k <= n; ++k) {
                for (int l = j; l <= m; ++l) {
                    int sumA = prefixSumA[k] - prefixSumA[i - 1];
                    int sumB = prefixSumB[l] - prefixSumB[j - 1];
                    int sum = sumA * sumB;
                    if (sum <= x) {
                        int area = (k - i + 1) * (l - j + 1);
                        maxArea = max(maxArea, area);
                    }
                }
            }
        }
    }
    cout << maxArea << endl;
    return 0;
}

L 阴晴不定的大橘学长

题目:https://ac.nowcoder.com/acm/contest/63602/L

解析:

前缀和变形加树状数组维护

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll n,x;
ll a[N],b[N],c[N],s[N];
void add(int x,int d){
	while(x<N){
		c[x]+=d;
		x+=x&-x;
	}
}
ll sum(int x){
	ll res=0;
	while(x){
		res+=c[x];
		x-=x&-x;
	}
	return res;
}
int main(){
	scanf("%lld%lld",&n,&x);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		b[i]=s[i]=s[i-1]+a[i];
	}
	sort(b,b+n+1);
	ll ans=0;
	for(int i=0;i<=n;i++){
		int k;
		if(i>0){
			k=upper_bound(b,b+n+1,s[i]-x)-b+1-1;
			ans+=sum(k);
		}
		k=lower_bound(b,b+n+1,s[i])-b+1;
		add(k,1);
	}
	printf("%lld\n",ans);
}

下一篇:牛客周赛 Round 7

推荐音乐:呓语

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值