最优 K 子段

  • 素数的密度约为ln(n),这就是说,1~n中素数的个数约为\(\frac {n}{ln(n)}\)
  • 观察你写出来的DP转移式,可以发现检查时没有必要DP,直接贪心就好了
  • 由于数据随机,最后十分钟“乱搞”两次成功过题,开心~
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int prime[20005],m;
int v[200005];
int a[200005],s[200005],f[200005];
int n,k;
int read1()
{
	char cc=getchar();
	while(!(cc>=48&&cc<=57))
	{
		if(cc=='-')
		{
			break;
		}
		cc=getchar();
	}
	bool f=false;
	int s=0;
	if(cc=='-')
	{
		f=true;
	}
	else
	{
		s=cc-48;
	}
	while(1)
	{
		cc=getchar();
		if(cc>=48&&cc<=57)
		{
			s=s*10+cc-48;
		}
		else
		{
			break;
		}
	}
	if(f==true)
	{
		s=-s;
	}
	return s;
}
bool check(int minn)
{
	int x=lower_bound(prime+1,prime+m+1,abs(minn)/10)-prime;
	int L=max(x-1200,1);
	int R=min(x+1200,m);
	for(int i=1;i<=n;i++)
	{
		f[i]=f[i-1];
		for(int j=L;j<=R&&prime[j]<=i;j++)
		{
			if(f[i-prime[j]]+1<=f[i])
			{
				break;
			}
			if(s[i]-s[i-prime[j]]>=minn)
			{
				f[i]=f[i-prime[j]]+1;
				break;
			}
		}
		if(f[i]>=k)
		{
			return true;
		}
	}
	return false;
}
int main()
{
	for(int i=2;i<=200000;i++)
	{
		if(v[i]==0)
		{
			v[i]=i;
			m++;
			prime[m]=i;
		}
		for(int j=1;j<=m;j++)
		{
			if(prime[j]>v[i]||i*prime[j]>200000)
			{
				break;
			}
			v[i*prime[j]]=prime[j];
		}
	}
	int T;
	cin>>T;
	while(T--)
	{
		cin>>n>>k;
		int smax=INT_MIN,smin=INT_MAX;
		int curmin=0,curmax=0;
		for(int i=1;i<=n;i++)
		{
			a[i]=read1();
			s[i]=s[i-1]+a[i];
			smax=max(smax,s[i]-curmin);
			smin=min(smin,s[i]-curmax);
			curmin=min(curmin,s[i]);
			curmax=max(curmax,s[i]);
		}
		if(n/2<k)
		{
			puts("impossible");
			continue; 
		}
		int l=smin,r=smax;
		while(l<r)
		{
			int mid=(l+r+1)>>1;
			if(check(mid))
			{
				l=mid;
			}
			else
			{
				r=mid-1;
			}
		}
		cout<<l<<endl;
	}
	return 0;
}
posted @ 2024-07-31 10:58  D06  阅读(18)  评论(0编辑  收藏  举报