现在的位置: 首页 > 综合 > 正文

codeforce 359D 二分+ 动态规划(sparse table)

2018年04月03日 ⁄ 综合 ⁄ 共 1521字 ⁄ 字号 评论关闭

原题链接:http://codeforces.com/problemset/problem/359/D

思路:首先对符合题目的长度(r-l)从0到n-1进行二分查找,对每一个长度进行check,看是否满足条件。

满足条件的话需要区间【l,r】内的最小值和最大公约数相等,如果暴力搜索,会超时,故采用st(sparse table)算法,建立table只需要O(nlgn)时间,查询是O(1),远远小于暴力搜索

st算法具体可参考http://baike.baidu.com/view/1536346.htm#2,只要适用于一段区间内的最大最小等值的计算。

AC代码如下:

#include <iostream>
#include <cstdio>
#include <iomanip>
#include <algorithm>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <string.h>
#include <math.h>
using namespace std;
typedef  long long ll;
const int MAXN = 300050;
int arr[MAXN];
int dp[MAXN][20];//gcd
int dq[MAXN][20];//min
int n;
int gcd(int a,int b)
{
	return b?gcd(b,a%b):a;
}
bool ok(int x)
{
	int k = (int)(log((double)(x+1)) / log(2.0));
	for(int i=0;i<n-x;i++)
	{
		int j = i+x;
		
		int Min = min(dq[i][k],dq[j - (1<<k) + 1][k]);
		int g = gcd(dp[i][k],dp[j - (1<<k) + 1][k]);
		if(g==Min)
			return true;
	}
	return false;
}
void out(int x)
{
	vector<int> v;
	int k = (int)(log((double)(x+1)) / log(2.0));
	if(x>0)
	{
		for(int i=0;i<n-x;i++)
		{
			int j = i+x;
			int Min = min(dq[i][k],dq[j - (1<<k) + 1][k]);
			int g = gcd(dp[i][k],dp[j - (1<<k) + 1][k]);
				if(g==Min)
				{
					v.push_back(i);
				}
		}
	}
	else
	{
		for(int i=0;i<n;i++)
			v.push_back(i);
	}
	cout<<v.size()<<" "<<( x>0?x:0)<<endl;
	for(int i=0;i<v.size();i++)
		cout<<v[i]+1<<" ";
	cout<<endl;
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
		cin>>arr[i];
	for(int i=0;i<n;i++)
	{
		dp[i][0] = arr[i];
		dq[i][0] = arr[i];
	}
	for(int i=1;i<20;i++)
		for(int j = 0;j<n;j++)
		{
			dp[j][i]=dp[j-1][i];
			dq[j][i] = dq[j-1][i];
			if(j+(1<<(i-1))<n)
			{
				dq[j][i] = min(dq[j][i-1],dq[j+(1<<(i-1))][i-1]); 
				dp[j][i] = gcd(dp[j][i-1],dp[j+(1<<(i-1))][i-1]);
			}

		}
		
	int l = 0;int r = n-1;
	while(l<r)
	{
		int mid = (l+r+1)/2;
		if(ok(mid))
			l = mid;
		else
			r = mid-1;
	}
		

	out(l);
	return 0;
}

抱歉!评论已关闭.