【题解】CF883I:Photo Processing

原题传送门
先排个序
最大值最小,用二分
然后用dp验证
d p i dp_i dpi表示当前到 i i i,最后一个分组是否可以以 i i i结尾
d p i ∣ = d p j − 1 ( j < i , a i − a j < = m i d ) dp_i|=dp_{j-1}(jdpi=dpj1(j<i,aiaj<=mid)
但是这个是 O ( n 2 ) O(n^2) O(n2)的,可以优化
发现对于一对 ( i , j ) ( i > j ) (i,j)(i>j) (i,j)(i>j),若 [ j , i ] [j,i] [j,i]无法分成一个组,那么 [ j , i + 1 ] [j,i+1] [j,i+1]一定也无法分成一组
可以把枚举 j j j的部分改成指针
l l l表示最小的可能转化给 i i i的, r = i − m + 1 r=i-m+1 r=im+1
每次如果 d p l − 1 = 0 , + + l dp_{l-1}=0,++l dpl1=0,++l

Code:

#include 
#define maxn 300010
#define LL long long
using namespace std;
int a[maxn], dp[maxn], n, m;

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

bool check(int mid){
	dp[0] = 1;
	int l = 1, r;
	for (int i = 1; i <= n; ++i){
		dp[i] = 0;
		while (a[i] - a[l] > mid) ++l;
		r = i - m + 1;
		for (int j = l; j <= r; ++j, ++l)
			if (dp[j - 1]){ dp[i] = 1; break; }
	}
	return dp[n];
}

int main(){
	n = read(), m = read();
	if (m == 1) return puts("0"), 0;
	for (int i = 1; i <= n; ++i) a[i] = read();
	sort(a + 1, a + 1 + n);
	int l = 0, r = a[n] - a[1], ans = 0;
	while (l <= r){
		int mid = (l + r) >> 1;
		if (check(mid)) r = mid - 1, ans = mid; else l = mid + 1;
	}
	printf("%d\n", ans);
	return 0;
}

你可能感兴趣的:(题解,codeforces,二分,题解,codeforces,二分,dp)