暑假考试题3:baritone 上低音号与星星(链表+矩形统计)

题目:

n,r,c<=3000

分析:先枚举左边界   然后将点从高到矮连链表   再统计从每一个点开始含括k个点的矩形   能够上下延伸得到的多少个矩形。
然后枚举右边界删点    利用大矩形原有的信息修改后    去累加新的左右宽度较小的矩形的贡献。

这种算法的优势: 每一次缩小矩形的时候 可以不用重新计算小矩形的贡献 只需要通过大矩形原有的贡献进行修改
修改方式:通过枚举右边界缩小矩形 删掉超出右边界范围内的那一列的点
删点时重新统计贡献 :也就是对被影响的点重新计算一下(通过跳链表找到受影响的点)

ys的图与详解

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 4005
int zong[N],x[N],y[N],r,c,n,k,q[N],val[N],nex[N],to[N],pre[N],num[N];
ll sum,ans=0;
vector<int>v[N];
bool cmp(int a,int b)
{
    if(q[a]==q[b]) return zong[a]<zong[b];
    return q[a]<q[b];
}
void del(int t)
{
    nex[pre[t]]=nex[t];//通过链表连边的方式删去t点
    pre[nex[t]]=pre[t];
    sum-=val[t];//删掉这个点 就应该把其贡献去掉
    int x=nex[t],y=nex[t];//跳nex是因为影响了下面一个点 因为下面一个点的上界是通过t来算的 t变了
    for(int i=1;i<=k-1;i++) y=nex[y];
    for(int i=1;i<=k+1;i++){
        int v=(q[x]-q[pre[x]])*(r-q[y]+1);
        //这个点原来的val就是这个点向右包含恰好k个点 然后向上下延伸得到的矩形个数
        sum+=v-val[x];// val贡献也应随着改变 所以应该重新统计一下x这个点的贡献
        val[x]=v;
        x=pre[x],y=pre[y];//因为t被删去了 所以前面通过t这个点向右延伸达到k个的val值都应该改变
    }
}
int main()
{
    freopen("baritone.in", "r", stdin);
    freopen("baritone.out", "w", stdout);
    int len=0;
    scanf("%d%d%d%d",&r,&c,&n,&k);
    for(int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]),v[y[i]].push_back(i);
    for(int i=1;i<=c;i++){//枚举左边界
        sum=0; len=0;
        for(int j=0;j<=20;j++)//防止越界 加入40个虚点 使得前面有20个点 后面有20个点
         q[++len]=0,q[++len]=r+1;
        for(int j=1;j<=n;j++)
        if(y[j]>=i){//如果这个点在枚举的左边界之内 就放入队列 维护相关信息
            q[++len]=x[j];//q是存的横坐标!!
            zong[len]=y[j];
            to[j]=len;//to是在链表中的编号
        }
        for(int j=1;j<=len;j++) num[j]=j;//num是每一个点的标号数组 便于对前len个在队列中的点 按横坐标为第一关键字排序
        sort(num+1,num+1+len,cmp);
        for(int j=1;j<=len-1;j++)
        nex[num[j]]=num[j+1],pre[num[j+1]]=num[j];//求每一个点的前驱和后继
        //for(int j=1;j<=len;j++) printf("%d ",pre[j]);
        nex[num[len]]=num[len];
        pre[num[1]]=num[1];
        for(int j=1;j<=len;j++){//接下来是答案的统计
            int now=j;
            for(int p=1;p<=k-1;p++)//跳k-1次恰好跳到的点 使得j和now之间恰好有k个点(包含它们本身) j和now是上下关系
            now=nex[now];
            val[j]=(q[j]-q[pre[j]])*(r-q[now]+1);
            //从pre[j]到 j表示 j可以向上延伸的长度 从q[now]到r是now向下可以延伸的长度
            //根据乘法原理累计答案 +1是因为有一方可以不延伸
            sum+=val[j];
        } //printf("ans:%lld\n",ans);
        for(int j=c;j>=i;j--){
            ans+=sum;
            for(int p=0;p<v[j].size();p++)//右边界向左移动 删去在这一列的所有点 因为下一次它们就超出范围了
            del(to[v[j][p]]);//找到第j列的所有点在链表中的编号 然后删掉 更新答案
        }
        //当右边界向左边界延伸的时候 其实是为了得到左右宽度更小的矩形答案 

    }
    printf("%lld\n",ans);
}
/*
3 2 3 3
1 1
3 1
2 2
*/

原文地址:https://www.cnblogs.com/mowanying/p/11405847.html

时间: 2024-07-31 06:26:23

暑假考试题3:baritone 上低音号与星星(链表+矩形统计)的相关文章

七中高新 NOIP模拟题 第二题 上低音号 题

由于这道题至今无人改掉(其实是没人想改),我就不去说题解了,只说说我当时考试的思路. 按照套路,先想暴力,很明显,枚举矩形形状再去暴力查询是人人都想得到的,但是复杂度O(n^4),而数据范围第一阶为n<=500,很明显,需要O(n^3)的复杂度,然后想到了类似扫描线的打发,完善后成功骗到30分. 我们可以先确定一下整个矩形的宽,然后去O(n^2)枚举宽所在的位置,再不断更新当前矩形的上边界的行数的最大值,我们就可以成功的在O(n^3)内完成答案统计. 至于k<=3的步骤分,我是真没想出来--

url上使用#号好不好

这是一篇摘自百度站长工具的文章. 一般来说,url当中的#号是一个锚点的标志位,这样的url打开之后会将访问者的视线定位在指定位置上,令访问者直接看到网页中间的一段内容.自从推特流行开始,#号被附予了新的意义——话题.很多站长直接在#号后面加参数且参数是有效的,即#号去掉与不去掉,打开的网页完全不同. 目前百度对带#号URL的收录策略是:去掉#号后面的内容,仅对#号前面的url进行建库.这样就导致一些站长认为有意义有价值的页面,百度却无法收录,继而影响新链接的抓取和整体SEO效果. 所以站长在建

从下往上增加的柱状图生成动画(适用于统计类应用)

我们在一些统计,理财应用中,经常能看到很多的柱状图,用来直观的标注信息,最近一个朋友刚好在做这方面的应用,跑来问我这个怎么实现,我笑他不就是简单的实现一个动画嘛,额,然后自己去做的时候才发现各种坑. 1.所有的UIView子类中,UILabel不能实现效果 2.创建View和对View实现的动画效果要放在一个方法中 3.增加的height和减少的top(顶部y坐标)必须成2倍关系 或者 增加的height和增加的bottom(底部y坐标)必须成2倍关系 @最后,直接上代码,大家可以去试验下,我也

java爬取网页上qq号,邮箱号等

import java.io.BufferedReader;import java.io.FileReader;import java.io.InputStreamReader;import java.net.URL;import java.net.URLConnection;import java.util.regex.Matcher;import java.util.regex.Pattern; public class GetMail { public static void main(S

暑假考试题2:Nim游戏 改(博弈论)

题目: 其实就是在nim游戏基础上添加了一次可以不取的机会. 多堆石子可以看成多个游戏,它们起点的sg值异或起来就是整个游戏的sg值,若sg值为1,则先手必胜,为0,则后手必胜. 关键在于怎么求sg值:可以打表找规律->对游戏局面进行动态dfs连边,再dfs一遍求sg值(也就是求mex值) 细节:dfs能跑到的范围很小,最多到20(可能还达不到,因为边实在是太多了),所以死循环时不要怀疑是自己打错了,还可能是石子数太大了. 规律:石子数为奇数,mex值为a[i]+1,偶数,mex值为a[i]-1

暑假考试题4:星际旅行(欧拉路)

题目: 分析: 题目大意:从任意点出发,任意点结束,在经过所有边的情况下选择两条边只经过一次,其它都经过两次. 先不考虑自环:这道题看起来很像欧拉路,但欧拉路是每条边只经过一次,那么我们考虑:把边数翻倍,选择两条边删去,使得剩下的是一个欧拉路. 边数翻倍后,每一个点的度数都是偶数 欧拉路的判定:只有两个点是奇数点,其它都是偶数点(奇偶指度数)证明 找不同的两条边删去,再考虑自环的因素,就应该分类讨论: 1.删两条边:通过画图推出,删的两条边一定是连在同一个点上,因为只有这样才会出现两个奇数点.

暑假考试题6:single 单(树上推理)

题目: 分析: 对于t=0的点,显然暴力会重复计算很多.设dis为一个点以下,所有儿子到它的val*dis和,sum为子树权值和,利用父亲已知的b与计算出的dis和sum来计算儿子的值.(必须要用bfs 保证更新的顺序) (当然我是做麻烦了的) 而t=1,要求知道b反推a,那么对一个点的b值进行分析,联立列方程去解a. 这里用到了一个重要的性质:根的b为∑i=2~n sum[i] (仔细想想可知) 然后一下就是关于如何解a的过程: #include<bits/stdc++.h> using n

线上应用bug跟踪查找-友盟统计

线上的应用只要用心点点都能发现些bug,连微信,QQ也不列外.但是bug中最严重的算是闪退了,这导致了用户直接不能使用我们的app. 我们公司是特别注重用户反馈和体验的,我们会定期打电话咨询用户的使用情况.我们也有自己的天使用户群,这些用户会跟我们及时的反馈应用的使用情况,bug情况,还有他们的需求. 用户不是技术人员他无法跟你清楚的描述怎么产生闪退的,于是我们需要一个bug统计的功能,我们公司采用友盟统计实现bug的记录.我们在iOS应用中植入友盟统计的功能,我也经常在查看友盟的错误统计和错误

ORACLE 根据上表不同的字段值的统计

select p.id comperitorId,p.compcorp competitorName, sum(case when c.kindname = 'ATM' then c.num else 0 end) atm, sum(case when c.kindname = 'CRS' then c.num else 0 end) crs, sum(case when c.kindname = 'VTM' then c.num else 0 end) vtm, sum(case when c