zoukankan      html  css  js  c++  java
  • Luogu P7244 章节划分

    这题从一月初看题解做到现在,必须写个题解纪念下。

    Link

    下文中 (sigma_k(x)) 表示 (x) 所有因数的 (k) 次方和。根据定义,(sigma_0(x)) 表示 (x) 所有因数的 (0) 次方和即 (x) 的因数数量。

    由于答案一定是 (max{a_i}) 的因数,所以 (mathcal O(sigma_0(max{a_i}))) 枚举答案 (x),转化为判定问题。定义一个区间 ([l,r]) 是合法的,当且仅当 ([l,r]) 的最大值 (y) 满足 (ymid x)。注意到两个合法的区间合并后仍然是合法的区间,所以可以设计一个 dp:令 (f(i)) 表示 (1sim n) 最多能分成多少个合法区间,那么转移方程为:

    [f(i)=maxlimits_{j=1}^{i-1}left{f(j)+[maxlimits_{k=j+1}^ileft{a_k ight}mod x=0] ight} ]

    上面这种转移的时间复杂度为 (mathcal O(n^2sigma_0(max{a_i}))) 的,考虑优化。令 (a_0=0)(p) 为满足 (a_p>a_i;(0le p<i)) 的最大的 (p),那么 ([1,p)) 的所有转移一定劣于 ([p,i-1]) 的转移,在 ([p,i-1]) 再分一段是更优的,而这个区间的 (max) 一定都是 (a_i),所以转移时只考虑 (f(p)sim f(i-1)) 即可,通过线段树维护可以实现 (mathcal O(nlog nsigma_0(max{a_i}))) 的时间复杂度。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N=1e5;
    int n,k,a[N+10];
    void Max(int &x,int y) {x=max(x,y);}
    
    //segment tree
    int m[N*4+10];
    void modify(int p,int l,int r,int ml,int d)
    {
    //	printf("modify(%d, %d, %d)
    ",p,l,r);
    	if(l==r)
    	{
    		m[p]=d;
    		return;
    	}
    	int mid=(l+r)/2;
    	if(ml<=mid) modify(p*2,l,mid,ml,d);
    	else modify(p*2+1,mid+1,r,ml,d);
    	m[p]=max(m[p*2],m[p*2+1]);
    }
    int query(int p,int l,int r,int ql,int qr)
    {
    	if(ql>qr) return -0x3f3f3f3f;
    	if(ql<=l && r<=qr) return m[p];
    	int mid=(l+r)/2,ans=-0x3f3f3f3f;
    	if(ql<=mid) Max(ans,query(p*2,l,mid,ql,qr));
    	if(qr>mid) Max(ans,query(p*2+1,mid+1,r,ql,qr));
    	return ans;
    }
    
    // stack
    int st[N+10],top=0,pre[N+10];
    void getpre()
    {
    	st[++top]=n;
    	for(int i=n-1;i;i--)
    	{
    		while(top && a[st[top]]<a[i]) pre[st[top--]]=i;
    		st[++top]=i;
    	}
    //	while(top) pre[st[top--]]=0;
    }
    
    // dp
    int dp[N+10];
    bool check(int x)
    {
    //	printf("x=%d
    ",x);
    	memset(dp,-0x3f,sizeof(dp));
    	dp[0]=0;
    	memset(m,-0x3f,sizeof(m));
    	for(int i=1;i<=n;i++)
    	{
    		if(pre[i]) Max(dp[i],dp[pre[i]]);
    		if(a[i]%x==0)
    		{
    			if(!pre[i]) Max(dp[i],1);
    			Max(dp[i],query(1,1,n,max(1,pre[i]),i-1)+1);
    //			printf("i=%d, query(%d, %d):%d
    ",i,max(1,pre[i]),
    //			i-1,query(1,1,n,max(1,pre[i]),i-1));
    		}
    //		printf("dp[%d]:%d
    ",i,dp[i]);
    		modify(1,1,n,i,dp[i]);
    	}
    //	for(int i=1;i<=n;i++) printf("%d ",dp[i]);
    //	putchar('
    ');
    	return dp[n]>=k; 
    }
    int main()
    {
    	scanf("%d %d",&n,&k);
    	int mx=0;
    	for(int i=1;i<=n;i++) 
    	{
    		scanf("%d",&a[i]); 
    		Max(mx,a[i]);
    	}
    	getpre();
    //	for(int i=1;i<=n;i++) printf("%d ",pre[i]);
    //	putchar('
    ');
    	for(int i=mx;i;i--)
    	{
    		if(mx%i) continue;
    		if(check(i))
    		{
    			printf("%d",i);
    			return 0;
    		}
    	}
    	return 0;
    }
    

    感谢:
    https://www.cnblogs.com/zzctommy/p/14226568.html
    https://www.luogu.com.cn/blog/cqbzljs/glr-round-2-luo-shui-zhi-ling-round-2-zhang-jie-hua-fen-ti-xie

  • 相关阅读:
    [ZROI 9.16模拟赛] Tutorial
    [ZROI 9.15模拟赛] Tutorial
    [USACO 2017 Open Gold] Tutorial
    [USACO 2017 Feb Gold] Tutorial
    [USACO 2017 Jan Gold] Tutorial
    [BZOJ 1208] 宠物收养所
    [BZOJ 1500] 维护序列
    多表查询
    sql查询语句查询顺序
    单表查询
  • 原文地址:https://www.cnblogs.com/juruo-zzt/p/14425544.html
Copyright © 2011-2022 走看看