暑假周测题解2

1.乐谱

题目:

农夫约翰打算教他的奶牛如何唱歌。歌曲包含\(N(1<=N<=100)\)个节拍,第 i 个节拍持续\(B_i(1<=B_i<=100)\)个音符。奶牛从第0时间开始唱歌,她们从第 0至\(B_1-1\)个时间唱第1个节拍,从第\(B_1\)\(B_1+B_2-1\)唱第2个节拍,依此类推。
奶牛们对唱歌已经失去了兴趣,因为他们觉得这首歌既长又无聊。因此,为了提高奶牛们的注意力,农夫约翰设计了一份\(Q(1<=Q<=1000)\)个问题的问卷,"从节拍T到节拍T+1之间,你知道演奏的是哪一个音符么?" 奶牛们非常需要你的帮助,不然她们就回答不了这些问题了。问题中\(T_i(0<=T_i<=10000)\)完全符合范围。

分析:

签到题,算一下前缀和,每次判断一下即可。

程序:

#include<bits/stdc++.h>
using namespace std;
int n,q,a[101],b[1001],f[101];
int main()
{
    cin>>n>>q;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        f[i]=f[i-1]+a[i];
    }
    for(int i=1;i<=q;i++)
        cin>>b[i];
    for(int i=1;i<=q;i++)
        for(int j=1;j<=n;j++)
            if(b[i]<f[j])
            {
                cout<<j<<'\n';
                break;
            }
    return 0;
}

2.起伏数

题目:

起伏数是在一对数字之间交替转换的数,如1212121,双重起伏数则是指在两种进制下都是起伏数的数,如十进制数191919是一个十进制下的起伏数,它对应的十一进制数121212也是一个起伏数,所以十进制数191919是一个双重起伏数。
类似的可以定义三重起伏数,三重起伏数在三种不同的进制中都是起伏数,甚至还有四重起伏数,如十进制300=606(七进制)=363(九进制)=454(八进制)=1A1(十三进制)…,你的任务就是在指定范围内找出双重、三重、四重起伏数。

题目条件:

1.输入条件:单独一行包含五个用空格隔开的十进制整数,前两个数表示进制的范围(2到32),第三与第四个数表示指定的范围(1到10000000),第五个数为2,3,4中的一个,表示要找的起伏数的重数。
2.输出条件:从小到大以十进制形式输出指定范围内的指定重数的起伏数。一行输出一个数。

分析:

暴力的方法就是直接枚举区间内的每一个数,接着枚举进制,把这个数的起伏数重数算出来即可,注意这里位数至少为3位,而且起伏数中的这一对数字不能是一样的。接下来我们换一个枚举的思路,一开始我们枚举每个数,现在我们可以先枚举进制,接着生成这个进制的起伏数,枚举进制,枚举第一个数,枚举第二个数,枚举位数,接着将这个数转化为十进制判断,很明显比刚才枚举一千万个数时间复杂度更优秀。这里有可能生成出重复的数,因此最好记录下来再判断。

程序:

#include<bits/stdc++.h>
using namespace std;
int l,r,p,q,m,a[51],ans[10001],s;
int zs(long long x,long long y,int s,int k)
{
	int sum=0;
	for(int i=s-1;i>=0;i--)
	{
		if((s-i)%2==1)
			sum+=x*pow(k,i);
		else
			sum+=y*pow(k,i);
		if(sum>q)
			return -1;
	}
	if(sum>=p)
		return sum;
	return -1;
}
bool check(int n,int x)
{
	int s=0,v=n;
	while(v)
	{
		a[++s]=v%x;
		v=v/x;
	}
	if(s<=2)
		return 0;
	for(int i=s;i>=3;i--)
		if(a[i]!=a[i-2]||a[i]==a[i-1])
			return 0;
	return 1;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>l>>r>>p>>q>>m;
	for(int k=l;k<=r;k++)
	{
		for(int i=1;i<k;i++)
			for(int j=0;j<k;j++)
				if(i!=j)
				{
					for(int h=1;h<=25;h++)
					{
						int v=zs(i,j,h,k);
						if(v==-1)
							continue;
						int t=0;
						for(int g=l;g<=r;g++)
							t+=check(v,g);
						if(t==m)
							ans[++s]=v;
					}
				}
	}
	sort(ans+1,ans+s+1);
	for(int i=1;i<=s;i++)
		if(ans[i]!=ans[i-1])
			cout<<ans[i]<<'\n';
	return 0;
}

3.幸运数字

题目:

数字4和7是幸运数字,而其他的都不是幸运数字。一个整数是幸运数字,当且仅当它的十进制表示只包含幸运数字。现在让你给出第K大的幸运数字。

题目条件:

第一行一个整数\(K(1<=K<=1000000000)\),30%的数据,K不超过100万。

分析:

我们可以一位位来构造这个第K大的幸运数字,然后先算出K的位数,如果K大于2就说明K至少是两位数,接着减去二,与22比较,以此类推,这样先求出k的位数,然后枚举每一位,从高位开始比较,如果现在是第i位,K比2i-1大,那就是7,否则就是4。

程序:

#include<bits/stdc++.h>
using namespace std;
int k,i=1;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>k;
	while(k)
	{
		if(k>pow(2,i))
		{
			k-=pow(2,i);
			i++;
		}
		else
			break;
	}
	while(i>0)
	{
		if(k>pow(2,i-1))
		{
			cout<<7;
			k-=pow(2,i-1);
		}
		else
			cout<<4;
		i--;
	}
    return 0;
}

4.电缆公司的烦恼

题目:

某地的居民决定举办一场程序比赛。评委会保证要组织一次最公正的比赛。它将选手的电脑以"星"形的结构连接并连到一个中心计算机。组织者决定将所有电脑以同样的距离连到该中心计算机上。组织者要求电缆公司提供一定量的等长的电缆,并希望电缆越长越好从而使选手之间的距离尽可能远。电缆公司的老板知道他的电缆长度精确到厘米,而且他能以厘米为单位切割电缆。但是这次他不知道所需的电缆的长度。郁闷的老板找到你,希望你能提供一个程序可以算出为达到所需求数量,这些电缆最多能被切成多长。

题目条件:

第一行N,K表示公司里的电缆数和所需的电缆数。n<=100000,k<=600000接下来N行为每根电缆的长度(1米到100千米之间),精确到厘米(小数点后2位)。

分析:

显然,题目的答案是有单调性的,可以二分,第一如果用小数来二分的话精度很难控制,因此我们可以把他变成整数进行二分,会减少很多麻烦。

程序:

#include<bits/stdc++.h>
using namespace std;
long long n,k,a[100001];
bool check(long long x)
{
	long long sum=0;
	for(int i=1;i<=n;i++)
		sum+=a[i]/x;
	if(sum>=k)
		return 1;
	return 0;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		double x;
		cin>>x;
		a[i]=x*100;
	}
	long long l=0,r=1e8;
	while(l<r)
	{
		long long mid=(l+r+1)/2;
		if(check(mid))
			l=mid;
		else
			r=mid-1;
	}
	cout<<fixed<<setprecision(2)<<l/100.0<<'\n';
    return 0;
}
posted @ 2026-08-10 21:06  zhhhanry  阅读(14)  评论(0)    收藏  举报