【 Codeforces Round #547 (Div. 3) F2】Same Sum Blocks (Hard)【思维贪心】

题目:

给定一个序列,从序列中选出几组连续不相交的区间,要求这几个区间中的数加起来一样大,问最多可以选出多少个区间。
( 1 N 1500 ) (1\leq N\leq 1500)


思路:

比赛的时候看到这题,直接就想到 D P DP 上去了… 但是实在没办法 D P DP ,然后自闭了…

很容易想到处理所有不同的区间和,然后对于每一个区间和再进行处理。因为最多只有 n 2 n^2 个不同的区间和,即最多 1 e 6 1e6 个不同的区间和,所以我们可以对于每个区间和进行处理。我也就是想到这里,然后转向了 D P DP

正解是对于每个区间和,处理出这个区间和对应的多个区间,然后问题就变成了经典的选课问题。现在有 n n 门课程,每门课程覆盖了一段时间,每个时间段只能上一门课,问最多可以选几门课。所以按照右端点排序,直接贪心即可。


反思:

D P DP 和贪心有的时候会难以区分,导致错失正解。 D P DP 的本质其实是搜索,是对暴搜的剪枝,去除了大量不正确的情况,通常来说列出了 D P DP 方程之后, D P DP 正确性也就随之证明了。但是对于贪心来说,很多时候还是停留在试试的阶段,对贪心的掌握还是很差。

贪心通俗来说,就是一种在每次决策时采取当前意义下最优策略的算法,因此贪心要求问题的整体最优性可以由局部的最优性导出,但是贪心的正确性其实并不好证明。通常采取微扰法进行证明,即邻项交换。证明在任意局面下,任何对局面最优策略的微小改变都会造成整体结果变差。


代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <map>
#include <algorithm>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
typedef long long ll;
typedef double db;
const db EPS = 1e-9;
using namespace std;
const int N = 2000;

int a[N],sum[N],n,tot;
map<int,int> mp;
vector<pair<int,int> > v[N*N];

int solve(int x){
	int tp = 0, last = 0;
	sort(v[x].begin(),v[x].end());
	rep(i,0,v[x].size()-1){
		if(v[x][i].second > last) tp++, last = v[x][i].first;
	}
	return tp;
}

void output(int x)
{
	if(x == -1) return;
	int last = 0;
	sort(v[x].begin(),v[x].end());
	rep(i,0,v[x].size()-1){
		if(v[x][i].second > last) {
			last = v[x][i].first;
			printf("%d %d\n",v[x][i].second,v[x][i].first);
		}
	}
}

int main()
{
	mp.clear(); tot = 0;
	scanf("%d",&n);
	rep(i,1,n){
		scanf("%d",&a[i]);
		sum[i] = sum[i-1]+a[i];
	}
	rep(i,0,n-1)
		rep(j,i+1,n){
			int tp = sum[j]-sum[i];
			if(mp.find(tp) == mp.end()) mp[tp] = ++tot;
			int pos = mp[tp];
			v[pos].push_back(make_pair(j,i+1));
		}
	int ans = 0, tph = -1;
	rep(i,1,tot){
		int tmp = solve(i);
		if(tmp > ans){
			ans = tmp, tph = i;
		}
	}
	printf("%d\n",ans);
	output(tph);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/88723087