题解:洛谷 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

【核心思想】

  1. 问题分析:给定 \(N \le 100\) 朵花排成一行,每朵花有花瓣数 \(p_i\)。对于所有连续子区间 \([i, j]\)\(1 \le i \le j \le N\)),若该区间内存在至少一朵花,其花瓣数等于该区间所有花花瓣数的平均值,则称这张照片“存在平均的花”。求满足条件的照片总数。本质是一个区间枚举 + 平均值判定问题,由于 \(N\) 很小,直接枚举所有区间并检查即可。

  2. 算法选择

    • 三重循环枚举:枚举所有区间 \([i, j]\),计算区间和 \(sum\) 与长度 \(len = j - i + 1\)。若 \(sum\) 能被 \(len\) 整除,则计算平均值 \(avg = sum / len\),然后遍历区间内所有元素,检查是否有 \(p_k == avg\)。一旦找到,答案加 1 并跳出内层检查循环。
    • 前缀和优化(可选):可使用前缀和数组 \(pref\) 将区间和计算降为 \(O(1)\),但 \(N=100\) 时直接累加也无性能问题。
  3. 关键步骤

    • 读入:读取 \(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
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N^3)\),最坏情况 \(N=100\),约 \(10^6\) 次操作,完全可行。
    • 空间复杂度:\(O(N)\),存储花瓣数。
  5. 枚举 + 平均值判定的核心思想

    • 直接模拟:由于数据范围小,最直观的做法是枚举所有区间并检查条件,无需复杂优化。
    • 整数判定:平均值必须是整数才可能等于某朵花的花瓣数(花瓣数为整数),因此用 \(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
posted @ 2026-08-30 09:19  团爸讲算法  阅读(4)  评论(0)    收藏  举报