2023级HAUT新生周赛(四)题解
A.我要成为复数高手
按照复数加法的运算规则运算即可,注意一些复数有简写形式:
1.当虚数的系数为1/-1时系数省略,
2.当实数部分的系数为0时,实数部分省略。
3.当虚数部分的系数为0时,虚数部分省略。
5.当虚数部分的符号为负数时,加号省略。
#include<stdio.h>
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int a, b,c,d,a1,a2;
scanf("%d %d %d %d",&a,&b,&c,&d);
a1 = a + c;
a2 = b + d;
if(a1==0)//实数部分系数为0
{
if(a2==1)
{
printf("i\n");
}
else if(a2==-1)
{
printf("-i\n");
}
else if(a2==0)//虚数系数的特殊情况。
{
printf("0\n");
}
else
{
printf("%di\n",a2);
}
}
else//实数部分为0
{
printf("%d",a1);
if(a2==0)
{
printf("\n");
}
else if(a2==-1)
{
printf("-i\n");
}
else if(a2==1)
{
printf("+i\n");
}//虚数系数的特殊情况。
else
printf("%+di\n",a2);
}
}
return 0;
}
B.依稀记得,那是一个烟雨蒙蒙的早晨。
签到题,根据自由落体公式输出5*t*t即可
#include<stdio.h>
int main()
{
int t;
scanf("%d",&t);
printf("%d\n",5*t*t);
return 0;
}
C.现在是幻想时刻。
考虑贪心,假设在第i个时刻卖出,那么一定在前i天股票价格最低时买入最佳,注意,如果最小值都大于现在剩余的钱,那么这个时候无法买入。枚举天数,记录前缀中的最小值,记录这个过程中的最大值即可。
#include<stdio.h>
int main()
{
int n,k;
scanf("%d %d",&n,&k);
int ans = 0;
int min1 = 1e7;
int x;
for(int i = 0;i<n;++i)
{
scanf("%d",&x);
if(x<=min1)
min1 = x;
if(min1<=k)
if(x-min1>=ans)
ans = x-min1;
}
printf("%d\n",ans);
return 0;
}
D 命运之夜
与运算:如果两个数a,b的第i位都为1,那么与运算之后,答案的第i位也为1.
或运算:如果两个数a,b的第i为中存在1个1,那么或运算之后,答案的第i位为1;
考虑a,b第i位的四种情况
- 1 1:与运算结果第i位为1,或运算结果第i位为1.
- 1 0 :与运算结果第i位为0,或运算结果第i位为1.
- 0 1:与运算结果第i位为0,或运算结果第i位位1.
- 0 0:与运算结果第i位为0,或运算结果第i为为0.
不难发现,与运算和或运算的答案内1的个数和与运算前a,b两数的1的个数和相同,
那么,我们可以先预处理出来每个数的二进制位含多少1,cnt数组记录一下,然后枚举以它为i时,大于i的部分有多少下标满足条件(有多少数的二进制中1的个数大于等于k-cnt[i])。让ans+=满足k-cnt[i]的个数即可。
#include<stdio.h>
long long arr[110000];
int cnt[90];//cnt[i]表示有多少数的二进制位中1的个数等于i。
int crr[110000];////crr[i]表示第i个数的二进制位中有多少1。
long long sum[90];//sum[i]表示有多少数的二进制位中1的个数大于等于i。
int main()
{
int n,k;
scanf("%d %d",&n,&k);
for(int i = 1;i<=n;++i)
{
scanf("%lld",&arr[i]);
int cnt1 = 0;
for(int j = 0;j<=30;++j)//计算每个数中有多少1
{
int c = (1<<j);
if(c&arr[i])
{
cnt1++;
}
}
crr[i] = cnt1;
cnt[cnt1]++;
}
for(int i = 70;i>=0;--i)
{
sum[i] = sum[i+1]+cnt[i];
}
int c = 0;
long long ans = 0;
for(int i = 1;i<=n;++i)
{
int t = k-crr[i];
for(int j = crr[i];j>=0;--j)//将自身减去。保证当前sum[i]表示的是大于i中有多少数的二进制位中1的个数大于等于i。避免重复。
{
sum[j]--;
}
if(t<0)
t = 0;
//cout<<t<<endl;
ans+=sum[t];
}
printf("%lld\n",ans);
return 0;
}
E 大富翁!启动!
影响最终收益的有当前所处的位置和当前已经获取的金币。
考虑动态规划,dp[i]表示到第i个点时小A可以获取多少收益。那么dp[i]的最大值会从dp[i-1],dp[i-2],dp[i-3],dp[i-4],dp[i-5],dp[i-6]中的最大值+第i格获取的金币。dp[n+1]即为终点。
注意,由于获取的金币可以为负数,需要初始化dp[i]为最小值。
#include<stdio.h>
long long arr[110000];
long long dp[110000];
int main()
{
int n;
scanf("%d",&n);
for (int i = 1; i <= n; ++i)
{
scanf("%lld",&arr[i]);
}
for (int i = 1; i <= n+10; ++i)
{
dp[i] = -1e12;
}
for (int i = 1; i <= n + 1; ++i)
{
for (int j = i - 1; j >= 0 && j >= i - 6; --j)
{
if(dp[j]>dp[i])
dp[i] = dp[j];
}
dp[i] += arr[i];
}
printf("%lld\n",dp[n+1]);
return 0;
}
F.历经千辛万苦,只为得到你
签到题,直接输出即可。
#include<stdio.h>
int main()
{
printf("AC!!!\n");
return 0;
}
G.火柴的奇怪用途.
由于n很小,考虑暴力,x,y,那么当n=24的时候,x,y最大可能是多少呢?由于1花费的火柴数最少,那么让x,y均为1111时,此时已经消耗16火柴,而且此时z的位数最小,但仍一共需要28根火柴,那么x,y一定不大于1111,从0开始枚举x,y时间复杂度为n方,可以通过这道题。
#include<stdio.h>
int main()
{
int a[2333]={0},b;
int c[10]={6,2,5,5,4,5,6,3,7,6};//预处理每个个数需要多少火柴。
int ans=0,i,p;
scanf("%d",&b);
for(i=0;i<=2222;i++)
{
p=i;
if(p==0)
a[p] = 6;
while(p>0)//求每个数所用的火柴棒
{
int d = p%10;
a[i]=a[i]+c[d];
p=p/10;
}
}
for(int i=0;i<=1111;i++)
{
for(int j=0;j<=1111;j++)
if(a[i]+a[j]+a[i+j]+4<=b)ans++;//X,Y,Z,加号与等号。
}
printf("%d",ans);
return 0;
}
H.奇怪的魔法书
s2串很小,直接暴力匹配即可。
如果ba可以等于s2,那么一定有ba的长度=s2的长度。
可以枚举后缀b,然后求出前缀a。然后把ba串与s2比较,如果一样,那么就让ans++即可。
#include<stdio.h>
#include<string.h>
int main()
{
char arr[110000];
char brr[110];
scanf("%s %s",arr,brr);
int m = strlen(brr);
int n = strlen(arr);
int ans = 0;
for(int i = 1;i<m;++i)//枚举后缀长度
{
int p = m-i;
char drr[1100] ={0};
int cnt = 0;
for(int j = 0;j<i;++j)
{
drr[cnt] = arr[n-i+j];
cnt++;
}
for(int j = 0;j<p;++j)
{
drr[cnt] = arr[j];
cnt++;
}
if(strcmp(drr,brr)==0)
{
ans++;
}
}
printf("%d\n",ans);
return 0;
}
查看2道真题和解析
牛客公司氛围 254人发布