zoukankan      html  css  js  c++  java
  • 【题解】CF1372E Omkar and Last Floor

    CF1372E Omkar and Last Floor

    ( ext{Solution:})

    首先一个显然的结论是让每一列的 (1) 的个数越多越好。

    证明: ((a+b)^2>a^2+b^2.)

    于是我们应该考虑的是怎么让一列的数的和最大。

    发现我们可以合并两个区间的答案,而数据范围这么小,很容易让人想到 (O(n^3)) 的算法。

    试着考虑区间 (dp:)(f[l][r]) 表示区间 ([l,r]) 的最大平方和。

    然后会发现:这个端点可能跨越了一些段,导致很难转移。

    于是我们更改一下:设 (f[l][r]) 为所有端点都在 ([l,r]) 内的线段组合的最大平方和。那么转移就是:

    [f[l][r]=max{ f[l][k-1]+f[k+1][r]+sum^2[l][r][k]} ]

    其中 (sum[l][r][k]) 代表区间 ([l,r]) 中跨越 (k) 的线段个数。

    考虑怎么处理这个东西:发现对于一个线段 (l,r,kin[l,r],[1,l-1]cup [r+1,m]) 内的端点才会有影响。

    考虑一个以 (l) 为横坐标 (r) 为纵坐标的坐标系,那影响的范围就是一个矩阵。二维前缀和即可。

    有一种神奇的写法:先前缀做出一条线的和,再扫成矩阵的面积。

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,f[101][101];
    int sum[101][101][101];
    struct line{int l,r;}p[101][101];
    int cnt[101];
    inline int Max(int x,int y){return x>y?x:y;}
    int main(){
    	freopen("111.txt","r",stdin);
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i){
    		int x;
    		scanf("%d",&x);
    		for(int j=1;j<=x;++j){
    			++cnt[i];
    			scanf("%d%d",&p[i][cnt[i]].l,&p[i][cnt[i]].r);
    		}
    	}
    	for(int i=1;i<=n;++i){
    		for(int j=1;j<=cnt[i];++j){
    			int l=p[i][j].l;
    			int r=p[i][j].r;
    			for(int k=l;k<=r;++k)sum[l][r][k]++;
    		}
    	}
    	for(int k=1;k<=m;++k){
    		for(int i=1;i<=m;++i){
    			for(int j=1;j<=m;++j){
    				sum[i][j][k]+=sum[i][j-1][k];
    			}
    		}
    		for(int i=m;i;--i){
    			for(int j=1;j<=m;++j){
    				sum[i][j][k]+=sum[i+1][j][k];
    			}
    		}
    	}
    //	for(int k=1;k<=m;++k){
    //		printf("%d:
    ",k);
    //		for(int i=1;i<=m;++i){
    //			for(int j=1;j<=m;++j)printf("%d ",sum[i][j][k]);
    //			puts("");
    //		}
    //	}
    	for(int i=1;i<=m;++i)f[i][i]=sum[i][i][i]*sum[i][i][i];
    	for(int len=2;len<=m;++len){
    		for(int l=1;l<=m-len+1;++l){
    			int r=l+len-1;
    			for(int k=l;k<=r;++k){
    				f[l][r]=Max(f[l][r],f[l][k-1]+f[k+1][r]+sum[l][r][k]*sum[l][r][k]);
    			}
    		}
    	}
    	printf("%d
    ",f[1][m]);
    	return 0;
    }
    
  • 相关阅读:
    高盛、沃尔玛 题做出来还挂了的吐槽
    amazon师兄debrief
    到所有人家距离之和最短的中点 296. Best Meeting Point
    问问题没人回答的情况怎么办终于有解了
    找名人 277. Find the Celebrity
    数组生存游戏 289. Game of Life
    547. Number of Provinces 省份数量
    428. Serialize and Deserialize Nary Tree 序列化、反序列化n叉树
    alias别名简介和使用
    面试官:线程池执行过程中遇到异常会发生什么,怎样处理? Vincent
  • 原文地址:https://www.cnblogs.com/h-lka/p/15008322.html
Copyright © 2011-2022 走看看