NOIP2017赛前模拟11月4日总结:

第一次挂0·····有点感伤···主要是因为时间分配太不合理了··花2个半小时搞第一题最后还wa完了··第二题很简单花了30分钟打完但没打对拍结果wa完···第三题暴力可以拿20分的但没时间打了···

第一次感受到了暴力的重要性··第一是想不出正解部分分是要拿的··第二是即使想出正解对拍也要用暴力···

以后考试决定遇到一道题先只想个20分钟·如果想不出正解先把暴力打了··三道题这样弄完后再去细细想正解

题目1:区间

  给定一个n个正整数的序列··q次询问两个数a,b,问序列中有多少个区间使得ab出现次数相等(0次也算),n<=8000,q<=500000

  先说暴力的方法··我们统计完前缀和后找出满足题意的区间lr为sum[a][r]-sum[a][l-1]=sum[b][r]-sum[b][l-1],移项后为sum[a][r]-sum[b][r]=sum[a][l-1]-sum[b][l-1],因此对于每次询问直接开一个桶记录每个两个数每一个位置的sum[a][i]-sum[b][i]的值的总数计算即可···顺便讨论一下ab是否存在于序列中的情况,注意ab有可能相等

  其实正解只是暴力的优化····这道题明显也想不出什么巧妙的方法··第一点是我们可以发现我们计算sum[a][i]-sum[b][i]的效果等效于我们在遍历每个位置时记录一个tag,遇到a的话+1,遇到b的话-1,每个位置上的tag值实际上就是sum[a][i]-sum[b][i],因此不用统计前缀和直接扫就可以了··第二点是我们可以发现暴力是对于每次询问我们是暴力O(n)扫过去的··其实可以发现中途的不是ab的位置实际上是多余的···因此我们完全可以开个数组记录每个数出现的位置(推荐用vector动态开··很方便··考试时脑子抽了写了个手动数组麻烦死··)对于询问的两个数将两个数的位置数组按序合并然后直接在位置数组上扫就可以了·····可以证明优化后的复杂度是n^2的

  代码:

#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<string>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
const int N=50005;
const int M=5e5+5;
inline int R(){
    char c;int f=0;
    for(c=getchar();c<‘0‘||c>‘9‘;c=getchar());
    for(;c<=‘9‘&&c>=‘0‘;c=getchar()) f=(f<<3)+(f<<1)+c-‘0‘;
    return f;
}
struct node{int x,y;}q[M];
vector<int>pos[N];
int tub[N*2],n,Q,b[N],cnt,num[N],tim,visit[N*2];
inline void lsh(){
    sort(b+1,b+cnt+1);
    cnt=unique(b+1,b+cnt+1)-b-1;
    for(int i=1;i<=n;i++) num[i]=lower_bound(b+1,b+cnt+1,num[i])-b;
}
int main(){
    n=R(),Q=R();
    for(int i=1;i<=n;i++) num[i]=R(),b[++cnt]=num[i];
    lsh();
    for(int i=1;i<=Q;i++){
        q[i].x=R(),q[i].y=R();
        int tx=lower_bound(b+1,b+cnt+1,q[i].x)-b;
        int ty=lower_bound(b+1,b+cnt+1,q[i].y)-b;
        if(b[tx]!=q[i].x) q[i].x=0;
        else q[i].x=tx;
        if(b[ty]!=q[i].y) q[i].y=0;
        else q[i].y=ty;
    }
    for(int i=1;i<=n;i++) pos[num[i]].push_back(i);
    for(register int i=1;i<=Q;i++){
        if((!q[i].x&&!q[i].y)||q[i].x==q[i].y){cout<<(n+1)*n/2<<endl;continue;}
        static int loc[N];int temp=0,a=q[i].x,b=q[i].y;
        register int head1=0,head2=0;
        while(head1<pos[a].size()||head2<pos[b].size()){
            if(head1==pos[a].size()){
                while(head2<pos[b].size()) loc[++temp]=pos[b][head2],head2++;
                continue;
            }
            if(head2==pos[b].size()){
                while(head1<pos[a].size()) loc[++temp]=pos[a][head1],head1++;
                continue;
            }
            if(pos[a][head1]>pos[b][head2]) loc[++temp]=pos[b][head2],head2++;
            else loc[++temp]=pos[a][head1],head1++;
        }
        if(!a||!b){
            long long ans=0;
            for(int i=1;i<=temp;i++) ans+=(loc[i]-loc[i-1]-1)*(loc[i]-loc[i-1])/2;
            ans+=(n-loc[temp])*(n-loc[temp]+1)/2;
            cout<<ans<<endl;
        }
        else{
            tim++;int maxx,minn,tag=N;
            tub[N]=1;visit[N]=tim;maxx=minn=N;long long ans=0;
            for(register int i=1;i<=temp;i++){
                if(num[loc[i]]==a){
                    tag++;maxx=max(maxx,tag),minn=min(minn,tag);
                    if(visit[tag]!=tim) tub[tag]=1,visit[tag]=tim;
                    else tub[tag]++;
                }
                else{
                    tag--;maxx=max(maxx,tag),minn=min(minn,tag);
                    if(visit[tag]!=tim) tub[tag]=1,visit[tag]=tim;
                    else tub[tag]++;
                }
                if(i!=temp)    tub[tag]+=loc[i+1]-loc[i]-1;
                else tub[tag]+=n-loc[i];
            }
            tub[N]+=loc[1]-1;
            for(register int i=minn;i<=maxx;i++)
                if(visit[i]==tim) ans+=tub[i]*(tub[i]-1)/2;
            cout<<ans<<endl;
        }
    }
    return 0;
}

题目2:排列

  给定n个数的排列的每个位置上的数的逆序数的前缀和(逆序数:前面的数中比该数大的数的个数),求出该排列····

  很简单的一道题··我们先将通过前缀和直接算出每个数的逆序数(从后往前一次用这个位置的前缀和减去下一个位置的前缀和考试的时候我是从前往后减的坑爹样例没有看出错),这时我们从后往前以此处理···很明显对于每个位置的逆序数a,我们知道它前面的数中有多少个数比它大从而知道了它的排名··直接用线段树区间查询k大值就可以了,再将它删除

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
inline long long R(){
    char c;long long f=0;
    for(c=getchar();c<‘0‘||c>‘9‘;c=getchar());
    for(;c<=‘9‘&&c>=‘0‘;c=getchar()) f=f*10+c-‘0‘;
    return f;
}
const int N=1e5+5;
int tree[N*4],n,anss[N],temp;
long long num[N];
inline void build(int k,int l,int r){
    if(l==r){
        tree[k]++;return;
    }
    int mid=(l+r)/2;
    build(k*2,l,mid);build(k*2+1,mid+1,r);
    tree[k]=tree[k*2]+tree[k*2+1];
}
inline void find(int k,int l,int r,int x){
    if(l==r){
        tree[k]--;temp=l;return;
    }
    int mid=(l+r)/2;
    if(x<=tree[k*2]) find(k*2,l,mid,x);
    else find(k*2+1,mid+1,r,x-tree[k*2]);
    tree[k]=tree[k*2]+tree[k*2+1];
}
int main(){
    //freopen("premu.in","r",stdin);
    //freopen("premu.out","w",stdout);
    n=R();
    for(int i=1;i<=n;i++) num[i]=R();
    for(int i=n;i>=1;i--) num[i]-=num[i-1];
    build(1,1,n);
    for(int i=n;i>=1;i--){
        find(1,1,n,i-num[i]);
        anss[i]=temp;
    }
    for(int i=1;i<=n;i++) cout<<anss[i]<<" ";
    return 0;
}

题目3:边的处理

  有一个n个点的无向图,给出m条边,每条边的信息形如x,y,c,r
  给出q组询问形如u,v,l,r
  接下来解释询问以及边的意义。 
  询问表示,一开始你在点u上,然后按顺序处理编号从l到r的边。 
  对于一条边xycr,你可以进行两次操作: 
  1、如果你当前在x点或者y点上,那么你可以走这条边(从x到y或从y到x)并付出c的代价(当然你也可以不走,看操作2)。 
  2、如果你不走这条边或者不可以走这条边(即你当前不在x或y上),那么你需要付出r的代价。 
  询问如果要从点u开始,按顺序处理完编号从l到r的边之后到达点v的最小代价,如果不能到达u,那么输出-1
  n<=30,m<=20000,q<=200000

  很好的分治题···

  暴力的话我们考虑对于每次询问的话每次处理到某一条边时所在点的所有的情况然后想最短路一样更新它到起点的距离

  分治的话挺复杂的,具体见http://blog.csdn.net/qq_35649707/article/details/78439108,%%%%%%%%%

  代码:

  

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=2e4+5;
const int N=2e5+5;
const int inf=0x3f3f3f3f;
inline int R(){
    char c;int f=0;
    for(c=getchar();c<‘0‘||c>‘9‘;c=getchar());
    for(;c<=‘9‘&&c>=‘0‘;c=getchar()) f=(f<<3)+(f<<1)+c-‘0‘;
    return f;
}
struct node{
    int x,y,c,r,u,v,l,id;
}ed[M],q[N];
int n,m,Q,f[M][35][35],anss[N];
inline void solve(int l,int r,int x,int y){
    if(x>y)    return;
    if(l==r){
        if(ed[l].x>ed[l].y) swap(ed[l].x,ed[l].y);
        for(int i=x;i<=y;i++){
            if(q[i].u>q[i].v) swap(q[i].u,q[i].v);
            if(q[i].l==l&&q[i].u==ed[l].x&&q[i].v==ed[l].y)    anss[q[i].id]=ed[l].c;
            if(q[i].u==q[i].v) anss[q[i].id]=min(anss[q[i].id],ed[l].r);
        }
        return;
    }
    static node d[N];int ri=y+1,le=x-1,mid=(l+r)/2;
    memset(f[mid],inf,sizeof(f[mid]));
    f[mid][ed[mid].x][ed[mid].y]=f[mid][ed[mid].y][ed[mid].x]=ed[mid].c;
    for(int i=1;i<=n;i++) f[mid][i][i]=min(f[mid][i][i],ed[mid].r);
    for(int i=mid-1;i>=l;i--){
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                f[i][j][k]=f[i+1][j][k]+ed[i].r;
        for(int j=1;j<=n;j++) f[i][ed[i].x][j]=min(f[i][ed[i].x][j],f[i+1][ed[i].y][j]+ed[i].c);
        for(int j=1;j<=n;j++) f[i][ed[i].y][j]=min(f[i][ed[i].y][j],f[i+1][ed[i].x][j]+ed[i].c);
    }
    memset(f[mid+1],inf,sizeof(f[mid+1]));
    f[mid+1][ed[mid+1].x][ed[mid+1].y]=f[mid+1][ed[mid+1].y][ed[mid+1].x]=ed[mid+1].c;
    for(int i=1;i<=n;i++) f[mid+1][i][i]=min(f[mid+1][i][i],ed[mid+1].r);
    for(int i=mid+2;i<=r;i++){
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                f[i][j][k]=f[i-1][j][k]+ed[i].r;
        for(int j=1;j<=n;j++) f[i][j][ed[i].x]=min(f[i][j][ed[i].x],f[i-1][j][ed[i].y]+ed[i].c);
        for(int j=1;j<=n;j++) f[i][j][ed[i].y]=min(f[i][j][ed[i].y],f[i-1][j][ed[i].x]+ed[i].c);
    }
    for(int i=x;i<=y;i++){
        if(q[i].l<=mid&&q[i].r>mid){
            anss[q[i].id]=inf;
            for(int j=1;j<=n;j++) anss[q[i].id]=min(f[q[i].l][q[i].u][j]+f[q[i].r][j][q[i].v],anss[q[i].id]);
        }
        else if(q[i].r<=mid) d[++le]=q[i];
        else d[--ri]=q[i];
    }
    for(int i=x;i<=le;i++) q[i]=d[i];
    for(int i=ri;i<=y;i++) q[i]=d[i];
    solve(l,mid,x,le);solve(mid+1,r,ri,y);
}
int main(){
    //freopen("a.in","r",stdin);
    n=R(),m=R(),Q=R();memset(anss,inf,sizeof(anss));
    for(int i=1;i<=m;i++) ed[i].x=R(),ed[i].y=R(),ed[i].c=R(),ed[i].r=R();
    for(int i=1;i<=Q;i++) q[i].u=R(),q[i].v=R(),q[i].l=R(),q[i].r=R(),q[i].id=i;
    solve(1,m,1,Q);
    for(int i=1;i<=Q;i++){
        if(anss[i]==inf||anss[i]<0) cout<<"-1"<<endl;
        else cout<<anss[i]<<endl;
    }
    return 0;
}
时间: 2024-10-12 03:09:51

NOIP2017赛前模拟11月4日总结:的相关文章

NOIP2017赛前模拟11月6日—7日总结

收获颇丰的两天··· 题目1:序列操作 给定n个非负整数,进行m次操作,每次操作给出c,要求找出c个正整数数并将它们减去1,问最多能进行多少操作?n,m<=1000000 首先暴力贪心肯定是每次减去数中前c大的数·· 因此我们考虑每次减去前c大的数后依然保持数列的有序性,假设数列为111223,c=5,为了保持有序性,2和3的部分可以正常减去1,但1的话我们需要从最左边开始减··· 所以对应每次操作,我们需要找到减去的最小的数的区间··从最左边开始减···这样就能保持有序性,直接在线段树上维护区

NOIP2017赛前模拟11月2日总结

分数爆炸的一天··但也学了很多 题目1:活动安排 给定n个活动的开始时间与结束时间··只有一个场地··要求保留尽量多的活动且时间不冲突···场地数n<=100000 考点:贪心 直接将结束时间按照升序排序,然后从小到大取不冲突的即可··很像hdu4343,然而我做的时候有点搞麻烦了 #include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctim

43_2013年11月22日 线程池 Socket(Thread Lock Process 摇奖 线程池ThreadPool)

1>模拟线程池,生产者消费者问题 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Product { class Program { static void Main(string[] args) { //创建一个池子 MyConncetion[]

平台和操作系统,是Google在2007年11月5日公布的手机系统平台,早期由Google开发,后由开放

Android是基于Linux内核[2]的软件平台和操作系统,是Google在2007年11月5日公布的手机系统平台,早期由Google开发,后由开放手机联盟(英语:Open Handset Alliance)(Open... kb.cnblogs.com/zt/andr... - 百度快照 - 91%好评 知识库_博客园 http://bbs.sssc.cn/thread-4458080-1-1.htmlhttp://bbs.sssc.cn/thread-4458079-1-1.htmlhtt

20141112,微软11月12日发布14个安全补丁

大家好,我们是微软大中华区安全支持团队. 微软于北京时间2014年11月12日发布了14个新的安全公告,其中4个为严重等级,8个为重要等级,共修复Microsoft Windows. Internet Explorer (IE). Office. .NET Framework, Internet Information Services (IIS).Remote Desktop Protocol (RDP). Active Directory Federation Services (ADFS)

2014年11月2日-11月9日 周总结

不敢相信一周的时间就这样过去了,只是简单的做了一个梦.醒来又是就是下周了. 周一周二所有的时间都是在准备地球制图的项目,周三编制制图报告.周四周五又都是在复习,准备地学信息分析与处理考试,一直都没有读书.一直到了周五晚上才有空读书.ArcGIS产品的白皮书,ENVI的产品白皮书和EV-Globe产品白皮书,粗略的浏览了一遍.又浏览了一下Matlab的帮助程序,收获很大,不过还是为了考试.值得高兴的是,计算机制图不需要考试,只需要交作品就好. 2014年11月10日-11月16日需要的事,AE二次

访问不了google的同学看过来(14年11月5日有效)

访问不了google的同学们,打开这个地址看看是什么?? 地址:https://edgecastcdn.net/00107ED/g/ 更新时间:2014年11月5日 喜大普奔阿, 访问不了的话,点此留言,随时更新 与本文相关的文章 Google开源工具nogotofail:可测试网络流量安全 Google是如何测试的(全) 微软和google的测试比较? Android SDK工具(Google提供的16个工具)简介 Android之父与Google的诀别内幕,***,google也留不住 值得

11月28日全球域名商保有量及市场份额排行榜TOP16

IDC评述网(idcps.com)12月01日报道:根据RegistrarStats公布的实时数据显示,截止至2015年11月28日,全球域名注册保有量十六强名单顺序,与上期11月21日保持一致,中国依旧占据3个席位,分别是中国万网.易名中国.新网,排名分列7..10.16名.下面,请看IDC评述网对数据的整理与分析. (图1)全球域名注册商(国际域名)保有量市场份额TOP16 如图1所示,截止至2015年11月28日,在全球域名注册市场上,GODADDY.COM份额依旧最大,第二名eNom与之

2014年11月12~11月14日,杨学明老师《软件测试管理》内训在北京某银行软件中心成功举办!

2014年11月12~11月14日,北京天气呈现少有的APEC蓝,著名研发管理专家杨学明老师为某银行提供了三天的内训服务,此次培训由两部分组成,第一部分是<软件测试管理高级实务>.第二部分是<软件测试需求分析和测试设计>,三天的培训非常紧张,包括老师讲解,案例演练,专题研讨,过程衔接非常紧密,课堂气氛也比较轻松,来自该银行核心系统和网银两个事业部的同事参加了此次培训,包括开发,需求,测试和维护人员等,课程结束后,举行了考试,大家对三天的学习进行回顾和总结,并准备把这两天学习到知识结