题解:洛谷 P9956 Daisy Chains
【题目来源】
洛谷:P9956 [USACO20DEC] Daisy Chains B - 洛谷
【题目描述】
每天,作为她绕农场行走的一部分,奶牛 Bessie 会经过她最喜爱的草地,其中种有\(N\)朵花(五颜六色的雏菊),编号为 \(1\dots N(1\le N\le 100)\),排列成一行。花\(i\)有\(p_i\)朵花瓣\((1\le p_i\le 1000)\)。
作为一名崭露头角的摄影家,Bessie 决定给这些花拍些照片。具体地说,对于每一对满足\(1\le i\le j\le N\) 的花 \((i,j)\),Bessie 会给从花\(i\) 到花 \(j\)之间的所有花(包括 \(i\)和\(j\))拍一张照。
后来 Bessie 查看这些照片时注意到有些照片里存在「平均」的花——一朵恰好有 \(P\) 朵花瓣的花,其中\(P\) 等于照片中所有花的花瓣数量的平均值。
Bessie 的照片中有几张存在平均的花?
【输入】
输入的第一行包含 \(N\)。第二行包含 \(N\)个空格分隔的整数 \(p_1,\dots,p_N\)。
【输出】
输出存在平均的花的照片数量。
【输入样例】
4
1 1 2 3
【输出样例】
6
【核心思想】
-
问题分析:给定 \(N \le 100\) 朵花排成一行,每朵花有花瓣数 \(p_i\)。对于所有连续子区间 \([i, j]\)(\(1 \le i \le j \le N\)),若该区间内存在至少一朵花,其花瓣数等于该区间所有花花瓣数的平均值,则称这张照片“存在平均的花”。求满足条件的照片总数。本质是一个区间枚举 + 平均值判定问题,由于 \(N\) 很小,直接枚举所有区间并检查即可。
-
算法选择:
- 三重循环枚举:枚举所有区间 \([i, j]\),计算区间和 \(sum\) 与长度 \(len = j - i + 1\)。若 \(sum\) 能被 \(len\) 整除,则计算平均值 \(avg = sum / len\),然后遍历区间内所有元素,检查是否有 \(p_k == avg\)。一旦找到,答案加 1 并跳出内层检查循环。
- 前缀和优化(可选):可使用前缀和数组 \(pref\) 将区间和计算降为 \(O(1)\),但 \(N=100\) 时直接累加也无性能问题。
-
关键步骤:
- 读入:读取 \(N\) 和数组 \(p[1..N]\)。
- 枚举左端点 \(i\) 从 1 到 \(N\):
- 初始化 \(sum = 0\)。
- 枚举右端点 \(j\) 从 \(i\) 到 \(N\):
- \(sum += p[j]\),\(len = j - i + 1\)。
- 若 \(sum \% len \neq 0\),则平均值非整数,跳过(因为花瓣数必须为整数)。
- 否则,计算 \(avg = sum / len\),然后遍历 \(k\) 从 \(i\) 到 \(j\),若存在 \(p[k] == avg\),则
ans++并跳出遍历。
- 输出答案:
ans。
-
时间/空间复杂度:
- 时间复杂度:\(O(N^3)\),最坏情况 \(N=100\),约 \(10^6\) 次操作,完全可行。
- 空间复杂度:\(O(N)\),存储花瓣数。
-
枚举 + 平均值判定的核心思想:
- 直接模拟:由于数据范围小,最直观的做法是枚举所有区间并检查条件,无需复杂优化。
- 整数判定:平均值必须是整数才可能等于某朵花的花瓣数(花瓣数为整数),因此用 \(sum \% len == 0\) 进行剪枝,避免浮点数运算。
- 存在性检查:只需知道区间内是否存在至少一个等于平均值的元素,找到即可停止,无需统计个数。
- 适用场景:适用于 \(N\) 较小(\(\le 200\))的连续子区间统计问题,核心是枚举所有区间并维护区间和。
【解题思路】

【算法标签】
普及- #模拟
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, a[105], ans=0;
int main()
{
cin >> n; // 输入n
for (int i=1; i<=n; i++) { // 遍历n朵花
cin >> a[i]; // 记录每朵花的花瓣数量
}
for (int i=1; i<=n; i++) { // 从1开始遍历
int avg=0, sum=0; // 每次初始化花瓣平均数和总数为0
for (int j=i; j<=n; j++) { // j从i开始向后遍历
sum += a[j]; // 计算花瓣总数
if (sum % (j-i+1)!=0) continue; // 如果平均数不为整数直接跳过(花的花瓣数不可能是小数)
avg = sum / (j-i+1); // 计算平均花瓣数
for (int k=i; k<=j; k++) { // 从i遍历到j
if (a[k]==avg) { // 如果有任一朵花恰好有p朵花瓣的花
ans += 1; // 照片数自增1
break; // 无需判断该照片中的其他花,直接结束循环
}
}
}
}
cout << ans << endl; // 打印结果
return 0;
}
【运行结果】
4
1 1 2 3
6
浙公网安备 33010602011771号