截断数列(c++前缀和)

截断数列

给定一个由 n位数字组成的序列 a1 a2 … an。

其中,每个数字都是 0∼9 之一。

请你判断,能否将数列从中间截断为两个或更多个非空部分,要求每一部分的各位数字之和都相等。

例如,350178 可以截断为 33 个部分 350、17、8,并且满足 3+5+0=1+7=8。

输入格式

第一行包含一个整数 n。

第二行包含 n 个数字 a1,a2,…,an,数字之间不含空格。

输出格式

如果可以按要求截断数列,则输出 YES,否则输出 NO

数据范围

前 66 个测试点满足 2≤n≤10。
所有测试点满足 2≤n≤100,0≤ai≤9。

输入样例1:
5
73452
输出样例1:
YES
输入样例2:
4
1248
输出样例2:
NO

题目来源于:https://www.acwing.com/problem/content/4304/

分析:

这个题的数据范围非常小,所以直接枚举即可。该题核心算法:前缀和

这里先简单介绍一下前缀和:

以原数组a[n],前缀和数组s[n]为例:

  1. 前缀和:s[i] = a[i]+a[i-1]。
  2. (l,r)区间和:s[l] = s[l] - s[r-1].
  3. a[n]数组下标从1开始。因为s[i] = a[i]+a[i-1] = a[i]。

如果对前缀和还不是很理解,可以看下这篇文章
c++灵活实现前缀和与差分

上代码

#include<iostream>
using namespace std;
const int N = 110;
int g[N];
int n;
bool flag;//用来判断是否找到一个方案。
string s;//由于没有空格,所以先当成一个字符串输入。

int main()
{
    cin>>n>>s;
    for(int i=0;i<n;i++) g[i+1] = s[i] - '0';//将字符串的每一个字符转换成int型数字。
    
    for(int i=1;i<=n;i++) g[i] += g[i-1];//求前缀和。
    
    for(int k=2;k<=n;k++)//枚举截断的段数。
    {
        if(g[n] % k != 0) continue;//找到一个k,可以使得前n项的和可以被其整除。
        
        int t = g[n]/k;//尝试分成k段,t就是每一段的和。
        
        for(int i=1;i<=n;i++)
        {
            if(g[i] != t) continue;//找到前缀和当中第一个等于t的数字。
            
            int e = g[i];//将第一个等于t的数字取出。
            
            for(int j = i + 1;j<=n;j++)//依次遍历找到下面的每一段等于t的区间
            {
                if(g[j] - e == t) e = g[j];//找到一个就把e更新到这个区间的尾部,下一次就从这个区间的尾部出发找下一个区间。
            }
            
            if(e == g[n]) flag = true;//每次找完如果最后一次更新的区间尾部刚好是g[n],说明找到了一种方案。
        }
    }
    
    if(flag == true) cout<<"YES";
    else cout<<"NO";
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值