第一次挂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=;
const int M=5e5+;
inline int R(){
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar()) f=(f<<)+(f<<)+c-'';
return f;
}
struct node{int x,y;}q[M];
vector<int>pos[N];
int tub[N*],n,Q,b[N],cnt,num[N],tim,visit[N*];
inline void lsh(){
sort(b+,b+cnt+);
cnt=unique(b+,b+cnt+)-b-;
for(int i=;i<=n;i++) num[i]=lower_bound(b+,b+cnt+,num[i])-b;
}
int main(){
n=R(),Q=R();
for(int i=;i<=n;i++) num[i]=R(),b[++cnt]=num[i];
lsh();
for(int i=;i<=Q;i++){
q[i].x=R(),q[i].y=R();
int tx=lower_bound(b+,b+cnt+,q[i].x)-b;
int ty=lower_bound(b+,b+cnt+,q[i].y)-b;
if(b[tx]!=q[i].x) q[i].x=;
else q[i].x=tx;
if(b[ty]!=q[i].y) q[i].y=;
else q[i].y=ty;
}
for(int i=;i<=n;i++) pos[num[i]].push_back(i);
for(register int i=;i<=Q;i++){
if((!q[i].x&&!q[i].y)||q[i].x==q[i].y){cout<<(n+)*n/<<endl;continue;}
static int loc[N];int temp=,a=q[i].x,b=q[i].y;
register int head1=,head2=;
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=;
for(int i=;i<=temp;i++) ans+=(loc[i]-loc[i-]-)*(loc[i]-loc[i-])/;
ans+=(n-loc[temp])*(n-loc[temp]+)/;
cout<<ans<<endl;
}
else{
tim++;int maxx,minn,tag=N;
tub[N]=;visit[N]=tim;maxx=minn=N;long long ans=;
for(register int i=;i<=temp;i++){
if(num[loc[i]]==a){
tag++;maxx=max(maxx,tag),minn=min(minn,tag);
if(visit[tag]!=tim) tub[tag]=,visit[tag]=tim;
else tub[tag]++;
}
else{
tag--;maxx=max(maxx,tag),minn=min(minn,tag);
if(visit[tag]!=tim) tub[tag]=,visit[tag]=tim;
else tub[tag]++;
}
if(i!=temp) tub[tag]+=loc[i+]-loc[i]-;
else tub[tag]+=n-loc[i];
}
tub[N]+=loc[]-;
for(register int i=minn;i<=maxx;i++)
if(visit[i]==tim) ans+=tub[i]*(tub[i]-)/;
cout<<ans<<endl;
}
}
return ;
}

题目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=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar()) f=f*+c-'';
return f;
}
const int N=1e5+;
int tree[N*],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)/;
build(k*,l,mid);build(k*+,mid+,r);
tree[k]=tree[k*]+tree[k*+];
}
inline void find(int k,int l,int r,int x){
if(l==r){
tree[k]--;temp=l;return;
}
int mid=(l+r)/;
if(x<=tree[k*]) find(k*,l,mid,x);
else find(k*+,mid+,r,x-tree[k*]);
tree[k]=tree[k*]+tree[k*+];
}
int main(){
//freopen("premu.in","r",stdin);
//freopen("premu.out","w",stdout);
n=R();
for(int i=;i<=n;i++) num[i]=R();
for(int i=n;i>=;i--) num[i]-=num[i-];
build(,,n);
for(int i=n;i>=;i--){
find(,,n,i-num[i]);
anss[i]=temp;
}
for(int i=;i<=n;i++) cout<<anss[i]<<" ";
return ;
}

题目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+;
const int N=2e5+;
const int inf=0x3f3f3f3f;
inline int R(){
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar()) f=(f<<)+(f<<)+c-'';
return f;
}
struct node{
int x,y,c,r,u,v,l,id;
}ed[M],q[N];
int n,m,Q,f[M][][],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+,le=x-,mid=(l+r)/;
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=;i<=n;i++) f[mid][i][i]=min(f[mid][i][i],ed[mid].r);
for(int i=mid-;i>=l;i--){
for(int j=;j<=n;j++)
for(int k=;k<=n;k++)
f[i][j][k]=f[i+][j][k]+ed[i].r;
for(int j=;j<=n;j++) f[i][ed[i].x][j]=min(f[i][ed[i].x][j],f[i+][ed[i].y][j]+ed[i].c);
for(int j=;j<=n;j++) f[i][ed[i].y][j]=min(f[i][ed[i].y][j],f[i+][ed[i].x][j]+ed[i].c);
}
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=;i<=n;i++) f[mid+][i][i]=min(f[mid+][i][i],ed[mid+].r);
for(int i=mid+;i<=r;i++){
for(int j=;j<=n;j++)
for(int k=;k<=n;k++)
f[i][j][k]=f[i-][j][k]+ed[i].r;
for(int j=;j<=n;j++) f[i][j][ed[i].x]=min(f[i][j][ed[i].x],f[i-][j][ed[i].y]+ed[i].c);
for(int j=;j<=n;j++) f[i][j][ed[i].y]=min(f[i][j][ed[i].y],f[i-][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=;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+,r,ri,y);
}
int main(){
//freopen("a.in","r",stdin);
n=R(),m=R(),Q=R();memset(anss,inf,sizeof(anss));
for(int i=;i<=m;i++) ed[i].x=R(),ed[i].y=R(),ed[i].c=R(),ed[i].r=R();
for(int i=;i<=Q;i++) q[i].u=R(),q[i].v=R(),q[i].l=R(),q[i].r=R(),q[i].id=i;
solve(,m,,Q);
for(int i=;i<=Q;i++){
if(anss[i]==inf||anss[i]<) cout<<"-1"<<endl;
else cout<<anss[i]<<endl;
}
return ;
}

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

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

    收获颇丰的两天··· 题目1:序列操作 给定n个非负整数,进行m次操作,每次操作给出c,要求找出c个正整数数并将它们减去1,问最多能进行多少操作?n,m<=1000000 首先暴力贪心肯定是每次 ...

  2. NOIP2017赛前模拟11月2日总结

    分数爆炸的一天··但也学了很多 题目1:活动安排 给定n个活动的开始时间与结束时间··只有一个场地··要求保留尽量多的活动且时间不冲突···场地数n<=100000 考点:贪心 直接将结束时间按 ...

  3. NOIP2017赛前模拟10月30日总结

    题目1: n个人参赛(n<=100000),每个人有一个权值··已知两个人权值绝对值之差小于等于K时,两个人都有可能赢,若大于则权值大的人赢···比赛为淘汰制,进行n-1轮·问最后可能赢的人有多 ...

  4. 11月30日《奥威Power-BI智能分析报表制作方法》腾讯课堂开课啦

    这么快一周就过去了,奥威公开课又要与大家见面咯,上节课老师教的三种报表集成方法你们都掌握了吗?大家都知道,学习的结果在于实际应用,想要熟练掌握新内容的要点就在于去应用它.正是基于这一要点,每一期的课程 ...

  5. 11月23日《奥威Power-BI报表集成到其他系统》腾讯课堂开课啦

    听说明天全国各地区都要冷到爆了,要是天气冷到可以放假就好了.想象一下大冷天的一定要在被窝里度过才对嘛,索性明天晚上来个相约吧,相约在被窝里看奥威Power-BI公开课如何?        上周奥威公开 ...

  6. 11月16日《奥威Power-BI基于SQL的存储过程及自定义SQL脚本制作报表》腾讯课堂开课啦

           上周的课程<奥威Power-BI vs微软Power BI>带同学们全面认识了两个Power-BI的使用情况,同学们已经迫不及待想知道这周的学习内容了吧!这周的课程关键词—— ...

  7. 11月09日《奥威Power-BI vs微软Power BI》腾讯课堂开课啦

    上过奥威公开课的同学可能有一个疑问:奥威Power-BI和微软Power BI是同一个吗,为什么叫同样的名字?正如这个世界上有很多个John.Jack.Marry…一样,奥威Power-BI和微软Po ...

  8. 2016年11月30日 星期三 --出埃及记 Exodus 20:21

    2016年11月30日 星期三 --出埃及记 Exodus 20:21 The people remained at a distance, while Moses approached the th ...

  9. 2016年11月29日 星期二 --出埃及记 Exodus 20:20

    2016年11月29日 星期二 --出埃及记 Exodus 20:20 Moses said to the people, "Do not be afraid. God has come t ...

随机推荐

  1. 【赛时总结】 ◇赛时·IV◇ CODE FESTIVAL 2017 Final

    ◇赛时-IV◇ CODE FESTIVAL 2017 Final □唠叨□ ①--浓浓的 Festival 气氛 ②看到这个比赛比较特别,我就看了一看--看到粉粉的界面突然开心,所以就做了一下 `(* ...

  2. Ubuntu安装MySQL及使用Xshell连接MySQL出现的问题(2003-Can't connect to MySql server及1045错误)

    不管在什么地方,什么时候,学习是快速提升自己的能力的一种体现!!!!!!!!!!! 以下所有的命令都是在root用户下操作(如果还没有设置root密码)如下: 安装好Ubuntu系统之后,打开终端先设 ...

  3. 文本处理工具-AWK

    awk简介 awk功能与sed相似,都是用来进行文本处理的.awk可以自动地搜索输入文件,并把每一个输入行切分成字段.许多工作都是自动完成的,例如读取每个输入行.字段分割. awk工作原理 awk一次 ...

  4. 交换机基础配置之单交换机划分vlan

    我们以以上拓扑图为例 pc0的IP地址为:192.168.1.1 pc1的ip地址为:192.168.1.2 两台主机在同一网段,相互ping是能ping通的 我们的目的是在单交换机上划分两个vlan ...

  5. [Bzoj4289]PA2012 Tax(Dijkstra+技巧建图)

    Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边 ...

  6. 29-自己动手构建RequestDelegate管道

    1-使用vsCode新建个项目 2-新建RequestDelegate和Context public delegate Task RequestDelegate(Context context); p ...

  7. 財務会計管理(FI&CO)

    FI(財務会計)系のSAP DBテーブル.随時更新していきます. [勘定コードマスタ]SKA1: 勘定コードマスタ(勘定コード表データ)SKB1: 勘定コードマスタ(会社コードデータ)SKAT: テキ ...

  8. java变量、数据类型

    public class Test { public static void main(String[] args) { //变量 //数据类型 变量名; //基本数据类型: //一个字节8位 //整 ...

  9. ElasticSearch学习笔记(四)-- 分布式

    1. 分布式介绍及cerebro cerebro插件 点击release下载 解压运行 访问9000端口,连接es的9200端口 2. 构建集群 新增一个节点 3. 副本与分片 再加入一个节点 4.  ...

  10. laravel5.5用户认证源码分析

    目录 1. 生成相关文件和配置 2. 分析路由文件 3. 以登陆开始为例,分析auth到底是怎么工作的 3.1 分析登录文件 3.2 分析门面Auth. 1. 生成相关文件和配置 快速生成命令 php ...