这是笔者在第一学期参加SCUACM 2023级 新生赛初赛写的一道题目。也是我写出来的第一道算法题目。
题目 构造
构建一个长度为的数组,数组元素只能为 1 或者 −1。
定义数组每满足一对为有1个特征A。求数组是否能构成出满足刚好k个特征A。
如果能构成该数组输出 YES 并给出构造数组。反之只输出 NO。
输入
每个测试包含多个测试用例。第一行包含测试用例的数量。测试用例说明如下。每个测试用例的唯一一行包含两个整数和--所需的数组长度和所需的A字符。
输出
对于每个测试用例,如果没有数组具有给定的A特征k,则打印 NO。
否则,打印 YES 和数字1和-1,它们组成所需的数组。如果有多个答案,则打印任意一个。
题目给出的特征A的表象之下,结合数组的特性,实际上可以得出:每两个相同的元素可以生成一个特征A。故只需要将数组分为两部分——一部分为p个1,另一部分为q个-1,则特征A的个数k的计算公式为:
代码思路就是去枚举不同的p,q来判断是否存在解,若枚举完之后仍然找不到符合条件的p和q,则打印 NO,否则打印 YES 之后先连续打印p个1,后连续打印q个-1即可。
笔者当时只浅学了C,并未涉及C++的知识,给出的代码如下:
#include <stdio.h>
#include <stdlib.h>
long long int comb(int m,int n)
{
long long int result;
if(m<=n) result = n*(n-1)/2;
else result = 0;
return result;
}
int judge(int n,int k){
for(int i=0;i<=n;i++){
if(k==(comb(2,i)+comb(2,n-i))){
printf("YES\n");
for(int j=1;j<=i;j++){
printf("1");
if(j!=n){
printf(" ");
}else printf("\n");
}
for(int j=i+1;j<=n;j++){
printf("-1");
if(j!=n){
printf(" ");
}else printf("\n");
}
return 0;
}
}
printf("NO\n");
return 0;
}
int main()
{
int t;
scanf("%d",&t);
int* n = (int*)malloc(t*sizeof(int));
int* k = (int*)malloc(t*sizeof(int));
for(int i=0;i<t;i++){
scanf("%d %d",&n[i],&k[i]);
}
for(int i=0;i<t;i++){
judge(n[i],k[i]);
}
free(n);
free(k);
return 0;
}
当时的代码水平很烂,尽管知道思路也还是试了三个小时才码对,由于C语言蹩脚的不可变数组,我研究了好一段时间才把n和k表示出来。
学习了C++并辅以不断的练习,这一次我只用了几分钟就码完了。
#include<bits/stdc++.h>
using namespace std;
struct ans{
bool found;
int p;
ans(bool iptB,int iptI){
found = iptB; p = iptI;
}
};
int Combination(int n){
return (n*(n-1)/2);
}
ans enumerate(int n,int k){
for(int i=0;i<=n;i++){
if(k == Combination(i) + Combination(n-i)) return ans(true,i);
}
return ans(false,0);
}
void generateNums(int n,int p){
for(int i=0;i<p;i++){
cout << "1 ";
}
for(int i=p;i<n;i++){
cout << "-1 ";
}
cout << endl;
}
int main(){
int t;
cin >> t;
vector<vector<int>> test(t,vector<int>(2));
for(int i=0;i<t;i++){
for(int j=0;j<2;j++){
cin >> test[i][j];
}
}
for(int i=0;i<t;i++){
ans answer = enumerate(test[i][0],test[i][1]);
if(answer.found){
cout << "YES" << endl;
generateNums(test[i][0],answer.p);
}
else cout << "NO" << endl;
}
return 0;
}
C++中的vector容器很实用,结构体也非常有用。
运用有意义的函数名和打包封装函数的方式能提升代码的可读性和层次性,使人一目了然。
同时我也确实感受到了在这三个月之间个人码力的提升,希望我能在今年四月份的转专业中如愿以偿。
感谢你能看到这里。