【牛客 - 181C】序列(前缀和,二分,可用set维护)(有坑)

49 篇文章 0 订阅
34 篇文章 0 订阅

题干:

小a有n个数,他想把他们划分为连续的权值相等的k段,但他不知道这是否可行。

每个数都必须被划分

这个问题对他来说太难了,于是他把这个问题丢给了你。

输入描述:

第一行为两个整数n,q,分别表示序列长度和询问个数。
第二行有n个数,表示序列中的每个数。
接下来的q行,每行包含一个数k,含义如题所示。

输出描述:

输出q行,每行对应一个数Yes或者No,分别表示可行/不可行

 

示例1

输入

复制

5 3
2 1 3 -1 4
3
2
1

输出

复制

Yes
No
Yes

备注:

 

对于的数据,

对于的数据,

对于的数据,

设ai表示数列中的第i个数,保证

保证数据完全随机

 

解题报告:

   刚开始以为二分复杂度是正确的,写了一个就AC了,但是后来一想发现不对啊复杂度成了O(q^2logn)、、、大概是数据水了吧

   而且我这种解法根本不适合有负数存在的情况、、因为sum数组就不单调了呀。

AC代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX = 100000 + 5 ;
ll a[MAX];
ll sum[MAX];
int main()
{
	int n,q,k;
	cin>>n>>q;
	for(int i = 1; i<=n; i++) scanf("%lld",a+i),sum[i] = sum[i-1] + a[i];
	while(q--) {
		scanf("%d",&k);
		if(sum[n] % k != 0) {
			puts("No");continue;
		}
		int every = sum[n] / k;
		int cur = 0,flag = 1;
		for(int i = 1; i<=k; i++) {
			int pos = lower_bound(sum+1,sum+n+1,cur + every) - sum;
			if(sum[pos] != cur+every) {
				flag=0;break;
			}
			cur += every;
		}
		if(flag == 1) puts("Yes");
		else puts("No");
	}

//	2 3 6 5 9
	return 0 ;
 } 

标程:(其实也差不多啦复杂度o(因子个数*N + q))

    其实就是打表算的,对于这题其实打表比较合适,因为q比n大,且题干中说了数据保证随机,所以最好是打表然后o(1)查询

#include<cstdio>
#include<cstring>
#include<algorithm> 
#define LL long long 
using namespace std;
const int MAXN = 2 * 1e6 + 10, INF = 1e9 + 10;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int a[MAXN];
bool ans[MAXN];
int main() {
    int N = read(), Q = read();
	LL sum = 0;
    for(int i = 1; i <= N; i++) a[i] = read(), sum += a[i];
    for(int i = 1; i <= N; i++) {
        if(sum % i != 0) {ans[i] = 0; continue;}
        LL cur = 0, k = 0;
        for(int j = 1; j <= N; j++) {
            cur += a[j];
            if(cur == sum / i) cur = 0, k++;
        }
        ans[i] = (cur == 0 && k == i);
    }
    while(Q--) {
    	int x = read();
    	puts(!ans[x] ? "No" : "Yes");
	}
}

数据保证随机的意思是 sum 的因子不会太多(构造数据可以达到1e5级别)
另外可能有一个坑点:因为有负数的存在,如果当前数大于了 sum/k 了,是不能直接跳出的(这是针对标程的解法的,用前缀和就不存在这个问题)

还是要注意一下负数啊!!各种题中,尤其是那种,说 int范围的。比如这题


不对啊,我那种方法其实修改一下也是正确的,用set维护一个pair<前缀,当前下标>,然后每次二分查找pair<那个值,上一次查找的下标>,这样找到的就是pair<那个值,那个下标后面的值>或者pair<大于那个值,下标无所谓>,我们在if判断一下是否是第一种,就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值