1. 程式人生 > >181C】序列(字首和,二分,可用set維護)(有坑)

181C】序列(字首和,二分,可用set維護)(有坑)

題幹:

小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判斷一下是否是第一種,就可以了。