7-15小测

本人小测分:50+40+17+5=123( ̄ー ̄)这个得分非常...

由于本人比较菜,所以本人将自己写的题解和我老师写的题解放在一起帮助各位学习

第1题 求和(hard)

给出 n 个整数,第 i 个数字为 A₁、A₂、…、An。每对数字之间有一个和谐度,定义如下:
对于一对数 (Ai, Aj),它们的和谐度 = (Ai and Aj) + (Ai or Aj) + (Ai xor Aj)
所有数的总和谐度是所有不同数对的和谐度之和(每对只算一次)。
现在你的任务是,对于给定的 n 个整数,求它们的总和谐度。

输入格式

第一行一个整数 n,表示有 n 个整数。
第二行 n 个整数 A₁, A₂, ..., An,表示每个数。

输出格式

输出一行一个整数,表示总和谐度。答案保证在 2⁶³-1 以内。

数据范围与约定

对于 50% 的数据,1 ≤ n ≤ 10,000
对于 100% 的数据,1 ≤ n ≤ 1,000,000,0 ≤ Aᵢ ≤ 30,000

思路:

1.首先我们把n个数纵向排列,然后分解为2进制,从最低位(也就是最右边)开始往高位一位一位截取,如样例1,2,3对应01,10,11最低位分别为1,0,1。我们知道and需要2个都为1才为1,所以这里3个数有2个为1,所以所有的方法数为C(2,2)只有一种,此时为第一位,二进制值为2^0,所以最低位And的和为11=1
2.我们再截取第二位,分别为0,1,1这时候也有2个1,那么所有组合方法有C(2,2)种,但此时是第二位,二进制值为2^1,所以第二位And和为1
2=2
所以此时这3个数所有对数的And和谐数为1+2=3
or和xor道理一样,分别从0和1中筛选数进行组合。

这道题用二进制拆位的方法找规律,我们就举and运算。
例:1,2,3,时二进制数是011011,如题计算是
(01&10)+(01&11)+(10&11)我们知道 and 需要 2 个都为 1 才为 1,所以二进制第一位的2个都为 1 才为 1的组合数是C(2,2)= 1,同理第二位也有C(2,2)= 1的组合数,所以(01&10)+(01&11)+(10&11)=C(2,2)*2^0+C(2,2)*2^1=3
orxor是道理一样,分别从0和1中筛选数进行组合。

代码:

#include<bits/stdc++.h>
using namespace std;
long long n,a[1000005],t=0,p=1;
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=63;i++)
	{
		long long b=0;
		for(int j=1;j<=n;j++)
		{
			if(a[j]%2==1)
			{
				b++;
			}
			a[j]/=2;
		}
		t=t+(b*(b-1))/2*p+(b*(n-b)+(b*(b-1))/2)*p+b*(n-b)*p;
		p=p*2;
		
	}
	printf("%lld",t);
	
	return 0;
}

第2题 头牛(cow)

农夫约翰有 N 头牛(2 ≤ N ≤ 10⁵)。每头牛的品种要么是 Guernsey(记作 G),
要么是 Holstein(记作 H)。通常情况下,牛站成一排,按顺序编号为 1 到 N。
在一天的过程中,每头牛都会写下自己的列表。具体来说,
第 i 头牛的列表包含从她自己(即第 i 头牛)开始,
到第 Eᵢ 头牛为止(包括 Eᵢ)。即第 i 头牛的列表区间为 [i, Eᵢ],其中 i ≤ Eᵢ ≤ N
农夫约翰发现,每种牛的品种都有一个独特的“领导者”。
FJ 不知道领导者是谁(每个品种中可能有多头牛可能成为领导者),
但他知道领导者一定符合以下两条规则之一:
领导者的列表包含另一种品种的领导者。
领导者的列表包含了所有和自己同品种的牛。

请你帮助 FJ 计算可能成为领导者的牛对数
(每种品种各选一个领导者,分别为一对)。保证至少有一对可能的领导者。

输入格式

第一行包含一个整数 N。
第二行包含一个长度为 N 的字符串,
第 i 个字符表示第 i 头牛的品种(G 表示 Guernsey,H 表示 Holstein)。
保证至少有一个 G 和一个 H。
第三行包含 N 个整数,E₁, E₂, ..., En。

输出格式

输出一个整数,表示可能的领导者对数。

思路:

image

据题意我们知道想当领导者就要满足自己的列表包含另一种品种的领导者自己的列表包含了所有和自己同品种的牛
我们将问题抽象一下,这个序列有两个领导者(一定是一前一后)那么后面那个领导者一定只能满足自己的列表包含了所有和自己同品种的牛 (都是废话) 那么它一定是自己同品种的牛中的第一个。反这想就是它前面一定没有和它同品种的牛,并且它一定不是第一个(因为还有一个比它前的领导),所以终结出第二个领导一定是与第一头牛另一种品种的牛
我们知道第一个领导一定是与第一头牛同品种的牛,所以我们只需找 1~与第一头牛不同品种的牛的下标-1 的第一个领导的方案数即可。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,r,l,t=0;
char a[200005];
int e[200005];
int main(){
	scanf("%d",&n);
    cin>>a+1;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&e[i]);
	}
	for(int i=1;i<=n;i++)
	{
		if(a[i]==a[1])r=i;
	}
	for(int i=2;i<=n;i++)
	{
		if(a[i]!=a[1])
		{
			l=i;
			break;
		}
	}
	for(int i=1;i<l;i++)
	{
		if((i==1&&e[i]>=r)||e[i]>=l)t++;
	}
	printf("%d",t);
	
	return 0;
}

第3题 K-th Number

给定一个包含 n 个元素的数组 a,请按照如下规则构建一个新的数组 b:
初始时,数组 b 为空。
对于数组 a 中每一个长度大于等于 k 的区间,找到该区间的第 k 大元素,并将这个元素添加到数组 b 中。
重复上述操作,直到所有满足条件的区间都被处理完毕。
最终,输出数组 b 中的第 m 大元素。

输入格式

第一行输入一个整数 T(1 ≤ T ≤ 10),表示数据组数。
每组测试数据包含两行:
第一行输入三个整数 n, k, m(1 ≤ n ≤ 100000,1 ≤ k ≤ n,1 ≤ m < 2 ^32)。
第二行输入 n 个整数 a1, a2, ..., an(1 ≤ ai ≤ 10 的 9 次方)。
保证数组 b 中存在第 m 大元素。

输出格式

对于每组测试数据,输出一行,表示数组 b 中的第 m 大元素。

思路:

image

我们可以用二分答案在用尺取法验证。(具体思路见代码)

代码:

#include<bits/stdc++.h>
using namespace std;
int T,n,k;
long long m,a[100005],b[100005];
bool d(long long x)
{
	int l=1,r=0,dm=0;
	long long dms=0;
	while(r<=n)//尺取验证
	{
		if(dm<k)//如果没找够k个数
		{
			if(r+1<=n&&a[r+1]>x)dm++;//记录比第m大的数大的数量
			r++;
		}
		else
		{
			if(dm==k)dms+=(n-r+1);
			if(dms>m-1)return 0;//不可能是第m大,也就是前面比第m大的数大的不只有(m-1)个
			if(a[l]>x)dm--;//弹出
			l++;
		}
	}
	return 1;
}
int main(){
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%lld",&n,&k,&m);
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&a[i]);
			b[i]=a[i];//因为要排序又要保持原状用于尺取所以又加了个数组
		}
		sort(b+1,b+1+n);//排序
		int l=1,r=n,mid;
		long long y=b[1];
		while(l<=r)//二分答案
		{
			mid=(r+l)/2;//二分第m大的
			if(d(b[mid]))
			{
				y=b[mid];
				r=mid-1;
			}
			else l=mid+1;
		}
		printf("%lld\n",y);
	}
	
	return 0;
}

第4题 背包问题(backpack)

kkkw最近研究学习背包问题。他有 n 个物品,第 i 个物品的价值为 a_i
kkkw在得知panda最近生活困难后,决定在这 n 个物品中挑选出价值和为 m 的物品装在背包里带给panda。
谁知kkkw在到panda家后,发现自己的背包破了一个洞,有一些背包里的物品(可能没有物品也可能所有是所有物品)遗失了。kkkw想知道,背包里剩余的物品的价值和可能是多少?

输入格式

第一行两个整数 n,m 。
接下来一行 n 个整数,a_1,a_2,...,a_n 表示每个物品的价值。

输出格式

共一行若干个整数,表示背包里剩余的物品的价值和可能是多少,按从小到大输出。

思路:

这道题可以用动态规划来写(具体看代码楼主不想写了)
image

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,f[510][510];
int main(){
	scanf("%d%d",&n,&m);
	f[0][0]=1;
	for(int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		for(int j=m;j>=x;j--)
		{
			for(int l=j;l>=0;l--)
			{
				f[j][l]|=f[j-x][l];
				if(l-x>=0)f[j][l]|=f[j-x][l-x];
			}
		}
	}
	for(int i=0;i<=m;i++)
	{
		if(f[m][i])printf("%d ",i);
	}
	
	return 0;
}

欢迎大家在评论区开喷

posted @ 2025-07-21 23:16  PLJZ  阅读(10)  评论(0)    收藏  举报