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

    这一整场比赛质量都很高,可以去看看,link

    P7244 章节划分

    比赛的时候被这题杀了/ll。赛后看完题解发现我是个傻逼,补完题回头一看提交数发现我是傻逼石锤了。

    首先应该想到答案一定是最大数的约数。暴力枚举只有 (240) 种情况,所以对每种情况以接近线性的复杂度判断是否合法即可。

    这个恰好 (k) 比较鬼畜。(k) 这一维显然不改开进状态。显然没有凸性所以不要想wqs二分。

    但是没想到就是个pj的贪心啊

    注意到相邻两个合法的段必然可以合并。所以只需要判断最多能分几段就好了!!!

    假设我们要判断 (gcd=x) 是否可行,令 (dp_i) 表示到 (i) 为之最多分几段。

    (dp_i=maxlimits_{0le j<i}(dp_j+[maxlimits_{j<kle i}{a_k}\%x=0]))

    非常显然有很多转移是白费的,具体来说,如果前面第一个大于 (a_i) 的数为 (a_{pre}) ,那么 ([0,pre]) 之内的转移都不优于 ([pre,i)) 之间的转移,因为 (pre) 这地方分一段显然更优。

    ([pre,i)) 之内的 (max) 必然是 (a_i) ,所以直接单调栈预处理 (pre) ,搞颗线段树维护一下区间最值,就没了woc这么智障的题考场上没切,我就是逊啊

    不过提一句,边界很烦,要小心。

    感谢 (color{black}{ exttt{G}}color{red}{ exttt{eorge1123}}) 的 hack数据

    3 2
    8 6 9
    

    答案是 (1)

    const int N=100005;
    const int T=N<<2;
    int n,k,a[N],MAX_A,dp[N],d[N],stk[N],top,pre[N],mxv[T];
    #define lc (p<<1)
    #define rc (p<<1|1)
    void change(int pos,int k,int l=1,int r=n,int p=1){
    	ckmax(mxv[p],k);
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	if(pos<=mid)change(pos,k,l,mid,lc);
    	else change(pos,k,mid+1,r,rc);
    }
    int query_max(int ql,int qr,int l=1,int r=n,int p=1){
    	if(ql<=l&&r<=qr)return mxv[p];
    	int mid=(l+r)>>1;
    	if(qr<=mid)return query_max(ql,qr,l,mid,lc);
    	if(mid<ql)return query_max(ql,qr,mid+1,r,rc);
    	return max(query_max(ql,qr,l,mid,lc),query_max(ql,qr,mid+1,r,rc));
    }
    bool check(int x){
    	memset(dp,-0x3f,(n+1)<<2),dp[0]=0,memset(mxv,-0x3f,sizeof(mxv));
    	for(int i=1;i<=n;++i){
    		if(pre[i]||a[i]%x==0)dp[i]=dp[pre[i]];
    		if(a[i]%x==0){
    			if(i==1)dp[i]=1;
    			else {
    				ckmax(dp[i],query_max(max(1,pre[i]),i-1)+1);
    				if(!pre[i])ckmax(dp[i],1);
    			}
    		}
    		change(i,dp[i]);
    	}
    	return dp[n]>=k;
    }
    signed main(){
    	n=read(),k=read();
    	rep(i,1,n)ckmax(MAX_A,a[i]=read());
    	for(int i=1;i<=n;++i){
    		while(top&&a[stk[top]]<=a[i])--top;
    		pre[i]=stk[top],stk[++top]=i;
    	}
    	for(int i=1;i*i<=MAX_A;++i){
    		if(MAX_A%i)continue;
    		d[++d[0]]=i;
    		if(i*i!=MAX_A)d[++d[0]]=MAX_A/i;
    	}
    	sort(d+1,d+d[0]+1,greater<int>());
    	for(int i=1;i<=d[0];++i)if(check(d[i]))return printf("%d
    ",d[i]),0;
    	cout<<-1;
    	return 0;
    }
    
  • 相关阅读:
    PacificA协议小结
    raft协议小结
    python爬虫抓取图片
    composer 的使用和常用命令大全
    php批量同步数据
    VMware虚拟机的安装与配置
    国家和地区代码表
    js判断h5页面地址的打开方式(微信、pc、移动端)
    phpexcel图片获取
    python的文件操作及简单的用例
  • 原文地址:https://www.cnblogs.com/zzctommy/p/14226568.html
Copyright © 2011-2022 走看看