zoukankan      html  css  js  c++  java
  • P5665 划分

    我爱卡常,卡常爱我

    题目大意

    给你 (n) 个数,需要找到一些分界点 (1 leq k_1 lt k_2 lt cdots lt k_p lt n) ,使得

    [sum_{i=1}^{k_1} a_i leq sum_{i=k_1+1}^{k_2} a_i leq cdots leq sum_{i=k_p+1}^{n} a_i ]

    并最小化

    [(sum_{i=1}^{k_1} a_i)^2 + (sum_{i=k_1+1}^{k_2} a_i)^2 + cdots + (sum_{i=k_p+1}^{n} a_i)^2 ]

    题解

    (part~1:O(n^3))

    我们可以定义 (f_{i,j}) 表示到第 (i) 个数,同时通过第 (j) 的点转移过来的最小值,我们可以易得状态转移方程:

    [egin{array}{c} f_{i,j}=min_{k=0}^{j-1}(f_{j,k}+(sum_i-sum_j)^2)\ s.t.~sum_j-sum_kle sum_i-sum_j end{array} ]

    由于我们是需要枚举 (i,j,k) 的,所以复杂度是 (O(n^3)) 的。

    预计得分:(36pts)

    (Part~2:O(n^2))

    我们可以发现,对于任意一个位置,最优解是满足最后一组最小的,所以我们可以记录对于每一个位置最后一组的转移点 (lst_i) ,那么转移方程就如下:

    [egin{array}{c} f_i=min_{j=0}^{i-1}(f_j+(sum_i-sum_j)^2)\ s.t.~sum_j-sum_{lst_j}le sum_i-sum_j end{array} ]

    预计得分:(64pts)

    (Part~3:O(n))

    对于上面 (dp) 方程的转移条件:

    [sum_j-sum_{lst_j}le sum_i-sum_j ]

    我们来移一下项:

    [sum_ige 2sum_j-sum_{lst_j} ]

    又因为 (sum) 数组是满足单调递增的,而且我们要找到最大的 (sum_j) 来使得 (sum_i-sum_j) 也就是最后一段最小,可以考虑单调队列优化,复杂度就为 (O(n)) 了。

    预计得分:(88pts)

    (Part~4:) 神仙卡常

    观察数据范围,我们发现肯定是要写高精的,然后我们发现恶心的出题人,非常善意的卡了你的空间又卡了你的时间。

    能开的符合题目条件的 (4 imes 10^7) 的数组你最多只能开两个,剩下的必须滚动或者直接一边算一边用。

    等你解决了 (MLE) 后,你会发现,如果你写的是高精,你会被卡常。然后我就毅然决然的压了 (10^8) 的位,同时加上了火车头,爱了爱了。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=4e7+5,M=1e5+5,MOD=(1<<30),EACH=1e9,LOG=5;
    struct lll
    {
    	int s[LOG];
    	int l;
    	void print() const
    	{
    		if(l==0)
    		{
    			printf("0");
    			return ;
    		}
    		for(int i=l;i>=1;--i)
    		{
    			printf("%lld",s[i]);
    		}
    		return ;
    	}
    	void operator = (const int &x)
    	{
    		memset(s,0,sizeof(s));
    		l=0;
    		int xx=x;
    		while(xx>0)
    		l++,xx/=EACH;
    		xx=x;
    		for(int i=1;i<=l;++i)
    		s[i]=xx%EACH,xx/=EACH;
    		return ;
    	}
    };
    lll ans;
    lll &operator + (const lll &a,const lll &x)
    {
    	ans=0;
    	int jinwei=0;
    	ans.l=max(a.l,x.l);
    	for(int i=1;i<=ans.l;++i)
    	{
    		ans.s[i]=a.s[i]+x.s[i]+jinwei;
    		jinwei=0;
    		if(ans.s[i]>=EACH)
    		{
    			jinwei=ans.s[i]/EACH;
    			ans.s[i]%=EACH;
    			if(i==ans.l)
    			++ans.l;
    		}
    	}
    	return ans;
    }
    lll &operator * (const lll &a,const lll &x)
    {
    	ans=0;
    	if(a.l==0||x.l==0)
    	return ans;
    	for(int i=1;i<=a.l;++i)
    	{
    		for(int j=1;j<=x.l;++j)
    		{
    			ans.s[i+j-1]+=a.s[i]*x.s[j];
    		}
    	}
    	int jw=0;
    	ans.l=a.l+x.l-1;
    	for(int i=1;i<=ans.l;++i)
    	{
    		ans.s[i]+=jw;
    		jw=0;
    		if(ans.s[i]>=EACH)
    		{
    			jw=ans.s[i]/EACH;
    			ans.s[i]%=EACH;
    			if(i==ans.l)
    			{
    				++ans.l;
    			}
    		}
    	}
    	return ans;
    }
    int n,type;
    int x,y,z,m;
    int a,b[3];
    int p,l,r;
    int lst[N],sum[N];
    int q[N],h=0,t=0;
    lll res,data;
    void special_read()
    {
    	scanf("%lld%lld%lld%lld%lld%lld",&x,&y,&z,&b[1],&b[2],&m);
    	for(int i=1,j=1;i<=n&&j<=m;++i)
    	{
    		while(p<i) scanf("%lld%lld%lld",&p,&l,&r);
    		if(i>=3)
    		b[i%3]=((x*b[(i-1)%3]%MOD+y*b[(i-2)%3]%MOD)%MOD+z)%MOD;
    		a=b[i%3]%(r-l+1)+l;
    		sum[i]=sum[i-1]+a;
    	}
    	return ;
    }
    void normal_read()
    {
    	for(int i=1;i<=n;++i)
    	scanf("%lld",&a),sum[i]=sum[i-1]+a;
    	return ;
    }
    signed main()
    {
    	cin>>n>>type;
    	if(type) special_read();
    	else normal_read();
    	q[h]=0;
    	for(int i=1;i<=n;++i)
    	{
    		while(h<t&&sum[q[h+1]]*2-sum[lst[q[h+1]]]<=sum[i]) h++;
    		lst[i]=q[h];
    		while(h<t&&sum[q[t]]*2-sum[lst[q[t]]]>=sum[i]*2-sum[lst[i]]) t--;
    		q[++t]=i;
    		// for(int j=0;j<i;++j)
    		// {
    		// 	if(sum[i]-sum[j]<lst[j])
    		// 	continue;
    		// 	if(f[i]>f[j]+(sum[i]-sum[j])*(sum[i]-sum[j]))
    		// 	f[i]=f[j]+(sum[i]-sum[j])*(sum[i]-sum[j]),
    		// 	lst[i]=sum[i]-sum[j];
    		// }
    	}
    	int tmp=n;
    	res=0;
    	while(tmp)
    	{
    		data=sum[tmp]-sum[lst[tmp]];
    		data=data*data;
    		res=res+data;
    		tmp=lst[tmp];
    	}
    	res.print(),printf("
    ");
    	return 0;
    }
    
  • 相关阅读:
    关于IE6不能兼容LCUC使用的PNG透明图象
    rmvb压制中高级技巧
    不错的课件网站
    C#程序多用户只启动一个进程的方法
    不可想像的加密光盘复制工具
    检测远程URL是否存在的三种方法
    请哪里有英文单词单复数转换的代码?
    一些感想,欢迎拍砖
    Some thoughts on my own O/R Mapping or Code Generation tools
    有了net send,谁还用IM?
  • 原文地址:https://www.cnblogs.com/Point-King/p/13532994.html
Copyright © 2011-2022 走看看