一些做过的题目

博客介绍了两个算法问题。一是将序列分成两个集合,使集合内元素满足特定条件,根据数据范围考虑复杂度,枚举数放入对应集合,若有不满足情况输出NO;二是计算序列子区间和为完全平方数的个数,先做前缀和,枚举平方数,遍历中更新出现个数,注意0的情况。

集合问题

登录—专业IT笔试面试备考平台_牛客网

题意:给定一个序列p,由n个数组成,给定一个整数a一个整数b。要你将这个序列分成两个集合,使得对于每个处于集合a的元素p,a - p也在集合a中,对于每个处于集合b的元素p, b - p也在集合b中,如果可以做到这件事情,输出YES,并且输出每个数处于的集合,属于集合a输出0, 属于集合b输出1。不能的情况输出no。

注意:当一个数放在a和放在b都行的时候,放在b

n的范围是1e5

根据数据范围,考虑nlogn或者n复杂度。我们可以枚举每一个数,如果在p序列当中找到满足能放进集合a或者能放进集合b的数,那么就把这两个数都放进那个集合,放进a集合,答案数组修改为0, 放进b集合,答案数组修改为1.

但凡出现一个数不能放在a也不能放在b,输出NO。

然后还有一个细节就是,ans数组要初始化为一个值,并且每次只有没被放进集合的数可以拿来操作。

珂朵莉与宇宙

登录—专业IT笔试面试备考平台_牛客网

题意:给你一个长为n的序列a,有n*(n+1)/2个子区间,问这些子区间里面和为完全平方数的子区间个数

题目说到子区间的和,所以必然先对a做前缀和。然后呢,枚举所有的平方数,由于平方数比较少,所以暴力的话复杂度也不会太高。对于每个s[i],如果s[i] - 平方数存在于s数组当中的话,那么答案就是存在的。

需要特别注意的一个点是,我们一定要在遍历的过程当中更新s[i]出现的个数,因为当枚举到i的时候,我们只考虑前i个数的区间中合法的值,而如果预处理s{i]出现的个数的话,就会把后面的值也加进来,那答案就会多算了。

所以在每次遍历到s[i] 的时候,st[s[i]]++, 还有一个要注意的是,0也是一个合法的值,也要记录个数。st[0]++

// Problem: 珂朵莉与宇宙
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/63391/C
// Memory Limit: 131072 MB
// Time Limit: 4000 ms

#include <bits/stdc++.h>
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define endl "\n"
#define PII pair<int, int>
#define fs first
#define sc second
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define all(x) (x).begin(), (x).end()
#define sz(x) ((int)(x).size())
#define YES                    \
    {                          \
        cout << "YES" << endl; \
        return;                \
    }
#define NO                    \
    {                         \
        cout << "NO" << endl; \
        return;               \
    }
#define pb push_back
using ull = unsigned long long;
using namespace std;
// head
int st[1000010];
void solve() {
    int n;
    cin >> n;
    vector<int> a(n + 1), s(n + 1);
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++) { s[i] = s[i - 1] + a[i]; }
    st[0]++;
    // for (int i = 1; i <= n; i++) { st[s[i]]++; }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int p = 0; p * p <= 1000000; p++) {
            if (s[i] - p * p >= 0) { ans += st[s[i] - p * p]; }
        }
        st[s[i]]++;
    }
    cout << ans << endl;
}

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int tt = 1;
    // cin >> tt;
    while (tt--) { solve(); }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值