- 周赛题解
【题解and标准程序】2025 SYNU 十一月冲刺周赛 Round II
- @ 2025-11-13 22:27:16
A. 千寻的猜数仪式 本题是一道二分加交互题,旨在让大家熟悉交互题
#include<bits/stdc++.h>
using namespace std;
int main() {
for (int l = 1, r = 1000000000, mid = (l + r) >> 1, res; l <= r; mid = (l + r) >> 1)
{
cout << mid << endl;
cin >> res;
if (res == 0)
{
return 0;
}
else if (res == -1)
{
l = mid + 1;
}
else if (res == 1)
{
r = mid - 1;
}
}
return 0;
}
B. 千寻的糖果试炼 记得开long long
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<long long> a(n);
for (int i = 0; i < n; ++i) cin >> a[i];
long long sum = a[0]; // 第一个孩子直接满足他自己的需求
long long prev = a[0]; // 前一个孩子的糖果数量
for (int i = 1; i < n; ++i) {
long long current = max(a[i], prev + 1);
sum += current;
prev = current;
}
cout << sum << endl;
return 0;
}
C. SYNU学员评测系统 我们先根据公式算出每一个人的标准差,然后进行排序即可。
在算标准差时,我们知道,本题只需要一个大小排名,并不需要每个人准确的标准差。因此,我们不必算,只需要算出 即可,也不需要考虑精度问题。
注意几个问题:
1.最后最多也只需要输出 20 个人,需要判断。
2.排序有两个关键字,先按标准差,再按姓名的字典序。
3.算标准差时需要使用 double 类型的变量。
#include <bits/stdc++.h>
using namespace std;
int n,m;
struct student
{
string name;//姓名
double sum;//标准差
}a[100001];
bool cmp(student x,student y)
{
if(x.sum!=y.sum)
return x.sum>y.sum;//第一个关键字,标准差降序排序
return x.name<y.name;//第二个关键字,当标准差相同时,字典序升序排序
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int b[25]={0},sum=0;//用b数组记录第i个人的每科成绩,sum为分数和
cin>>a[i].name;
for(int j=1;j<=m;j++)
{
cin>>b[j];
sum+=b[j];
}
double pjz=(sum*1.0)/(m*1.0);//求平均值,要考虑int转double的问题
for(int j=1;j<=m;j++)
a[i].sum+=(pjz-b[j])*(pjz-b[j]);
}
sort(a+1,a+1+n,cmp);//排序
for(int i=1;i<=min(20,n);i++)
cout<<a[i].name<<endl;//输出前20人
return 0;
}
D. Chihiro 的糖果分配 这道题我们可以用dp:
f[i][x] 表示 i 分成 x 个非空的数的方案数。
显然 i<x 时 f[i][x]=0 , i=x 时 f[i][x]=1;
其余的状态,我们分情况讨论:
①方案中有1的 ②方案中没有1的
第一种情况,方案数为 f[i-1][x-1]
第二种情况,方案数为 f[i-x][x] (此时 i 必须大于 x)
所以,状态转移方程为: f[i][x]=f[i-1][x-1]+f[i-x][x]
#include<bits/stdc++.h>
using namespace std;
int n,k,f[201][7];
int main(){
cin >> n >> k;
for(int i=1;i<=n;i++)
{
f[i][1]=1;
f[i][0]=1;
}
for(int x=2;x<=k;x++)
{
f[1][x]=0;
f[0][x]=0;
} // 边界,为了防止炸,把有0的也处理了
for(int i=2;i<=n;i++)
for(int x=2;x<=k;x++)
{
if(i>x)
f[i][x]=f[i-1][x-1]+f[i-x][x];
else
f[i][x]=f[i-1][x-1];
}
cout<<f[n][k];
return 0;
}
E. Chihiro与Orange之间的游戏 首先明确,只要还有石子,那么一定能取 不妨设有两堆石子a1,a2,假设现在还有石子且无法取 那么有a1+a2≥0,a2<a1<0 ①两不等式矛盾:两个负数相加必定不是非负数 ②石子数不可能为负数 所以只要还有石子,就一定能取 那么问题就转换为两人轮流从一堆石子取一粒,谁先不能取谁输 我们可以假设石子一共有x粒,甲取了k粒 若是甲赢,那么甲一定比乙多取了一颗,得x=2k+1,x为奇数 若是乙赢,那么甲一定和乙取的石子数一样,得x=2k,x为偶数 就推出了双方赢的充要条件
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a,n;
long long sum=0;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a;
sum+=a;
}
if(!(sum&1))//利用位运算优化
{
cout<<"Orange"<<endl;
}
else
{
cout<<"Chihiro"<<endl;
}
return 0;
}
F. Chihiro 的平方奇想 我们先按 k 的奇偶性分讨一下: 如果 k 2=1,那么设中间的数为 mid,就可以算出这 k 个数的和为 k × mid,为了让这个和为完全平方数,所以 mid 最小要为 k,之后就去枚举 ×、×、×,直到最后一个数超过 n。 如果 k 2=0,那么还是设中间的两个数为 mid 和 mid+1,那这 k 个数的和是 ,然后把 2k 提取出来,因为它是个常数,不会变,然后就找与 相乘为完全平方数的最小值,之后还是枚举 ×、×、×,再判一下是否有解。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, k, sum, now = 1, ans;
signed main() {
scanf("%lld%lld", &n, &k);
if(k % 2 == 1)
{
for(int i = 1; ; i++)
{
if(k * i * i + k / 2 <= n)
sum++;
else
break;
}
printf("%lld", sum);
}
else
{
int l = k / 2;
for(int i = 2; i * i <= k; i++)
while(l % (i * i) == 0)
l /= i * i;
if(l % 2 == 0)
{
printf("0");
return 0;
}
for(int i = 1; ; i += 2)
{
ans = i * i * l;
if(ans < k + 1)
continue;
if(ans / 2 + k / 2 <= n)
sum++;
else
break;
}
printf("%lld", sum);
}
}